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 !*.lib
# Resources bin # 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" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </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" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

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

View File

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

View File

@ -14,8 +14,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kiwano-physics", "kiwano-ph
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}"
EndProject 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}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtinyxml2", "3rd-party\tinyxml2\libtinyxml2.vcxproj", "{AB47E875-85E5-4105-A71E-88930EAAB910}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libimgui", "3rd-party\imgui\libimgui.vcxproj", "{7FA1E56D-62AC-47D1-97D1-40B302724198}" 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}.Debug|Win32.Build.0 = Debug|Win32
{A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.ActiveCfg = Release|Win32 {A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.ActiveCfg = Release|Win32
{A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.Build.0 = Release|Win32 {A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.Build.0 = Release|Win32
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Debug|Win32.ActiveCfg = Debug|Win32 {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.ActiveCfg = Debug|Win32
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Debug|Win32.Build.0 = Debug|Win32 {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.Build.0 = Debug|Win32
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Release|Win32.ActiveCfg = Release|Win32 {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.ActiveCfg = Release|Win32
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Release|Win32.Build.0 = 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.ActiveCfg = Debug|Win32
{AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.Build.0 = Debug|Win32 {AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.Build.0 = Debug|Win32
{AB47E875-85E5-4105-A71E-88930EAAB910}.Release|Win32.ActiveCfg = Release|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}.Debug|Win32.Build.0 = Debug|Win32
{0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.ActiveCfg = Release|Win32 {0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.ActiveCfg = Release|Win32
{0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{3A3948DC-9865-46B3-B7B9-7E5572704ED2} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
{AB47E875-85E5-4105-A71E-88930EAAB910} = {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} {7FA1E56D-62AC-47D1-97D1-40B302724198} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
{A9ABACC7-75A1-46BA-8E48-4105346D9719} = {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"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <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\AudioEngine.h" />
<ClInclude Include="..\..\src\kiwano-audio\kiwano-audio.h" /> <ClInclude Include="..\..\src\kiwano-audio\kiwano-audio.h" />
<ClInclude Include="..\..\src\kiwano-audio\Sound.h" /> <ClInclude Include="..\..\src\kiwano-audio\Sound.h" />
@ -19,7 +19,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<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\AudioEngine.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\Sound.cpp" /> <ClCompile Include="..\..\src\kiwano-audio\Sound.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\SoundPlayer.cpp" /> <ClCompile Include="..\..\src\kiwano-audio\SoundPlayer.cpp" />
@ -39,7 +39,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup> </PropertyGroup>
@ -108,4 +108,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,14 +3,19 @@ function Set-FileConfiguration {
[string]$filePath [string]$filePath
) )
$replace = "<DebugInformationFormat>(EditAndContinue|ProgramDatabase)</DebugInformationFormat>" $debugInfoReplace = "<DebugInformationFormat>(EditAndContinue|ProgramDatabase)</DebugInformationFormat>"
$replaceTo = "<DebugInformationFormat>None</DebugInformationFormat>" $debugInfoReplaceTo = "<DebugInformationFormat>None</DebugInformationFormat>"
$optimizationReplace = "<WholeProgramOptimization>true</WholeProgramOptimization>"
$optimizationReplaceTo = "<WholeProgramOptimization>false</WholeProgramOptimization>"
# Create a copy of .vcxproj file # Create a copy of .vcxproj file
Copy-Item -Path $filePath -Destination ($filePath + '.template') Copy-Item -Path $filePath -Destination ($filePath + '.template')
# Overlay some configurations # 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 # Delete the copy file
Remove-Item -Path ($filePath + '.template') Remove-Item -Path ($filePath + '.template')
@ -24,3 +29,12 @@ Get-ChildItem -Path 'projects\' -Directory | ForEach-Object {
Set-FileConfiguration ($dirPath + '\' + $_) 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 // Copyright (c) 2019-2020 OuterC - 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 #pragma once
#include <typeinfo> #include <typeinfo>
#include <type_traits> #include <type_traits>
#include <exception> #include <exception>
namespace kiwano namespace oc
{
namespace common
{ {
class bad_any_cast : public std::exception class bad_any_cast : public std::exception
@ -133,7 +112,7 @@ public:
template <typename _Ty> template <typename _Ty>
const _Ty* cast_pointer() const noexcept 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(); const type_info* const info = typeinfo();
if (info && (*info == typeid(std::decay<_Ty>::type))) if (info && (*info == typeid(std::decay<_Ty>::type)))
@ -519,14 +498,14 @@ _Ty any_cast(any&& a)
return static_cast<_Ty>(std::move(*ptr)); return static_cast<_Ty>(std::move(*ptr));
} }
} // namespace common } // namespace oc
} // namespace kiwano
namespace std namespace std
{ {
inline void swap(kiwano::common::any& lhs, kiwano::common::any& rhs) noexcept
{ inline void swap(oc::any& lhs, oc::any& rhs) noexcept
lhs.swap(rhs); {
} 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 // Copyright (c) 2019-2020 OuterC - 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 #pragma once
#include <memory> #include <memory>
#include <type_traits> #include <stdexcept>
#include <exception> #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<> // vector<>
// Lightweight std::vector<>-like class // Lightweight std::vector<>-like class
// //
template< template <typename _Ty, typename _Alloc = std::allocator<_Ty>>
typename _Ty,
typename _Alloc = std::allocator<_Ty>,
typename _Manager = __vector_details::vector_memory_manager<_Ty, _Alloc>>
class vector class vector
{ {
public: public:
@ -59,7 +25,7 @@ public:
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using allocator_type = typename _Alloc; 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>; using initializer_list = std::initializer_list<value_type>;
public: public:
@ -74,11 +40,11 @@ public:
template <typename _Iter> template <typename _Iter>
inline vector(_Iter first, _Iter last) : vector() { assign(first, last); } 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=(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& 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(const vector& src) { return operator=(src); }
inline vector& assign(initializer_list list) { return operator=(list); } inline vector& assign(initializer_list list) { return operator=(list); }
@ -140,8 +106,8 @@ protected:
_Ty* data_; _Ty* data_;
}; };
template<typename _Ty, typename _Alloc, typename _Manager> template<typename _Ty, typename _Alloc>
void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val) void vector<_Ty, _Alloc>::resize(size_type new_size, const _Ty& val)
{ {
if (new_size > size_) if (new_size > size_)
{ {
@ -158,8 +124,8 @@ void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val)
size_ = new_size; size_ = new_size;
} }
template<typename _Ty, typename _Alloc, typename _Manager> template<typename _Ty, typename _Alloc>
void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) void vector<_Ty, _Alloc>::reserve(size_type new_capacity)
{ {
if (new_capacity <= capacity_) if (new_capacity <= capacity_)
return; return;
@ -167,8 +133,7 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity)
auto new_data = manager::allocate(new_capacity); auto new_data = manager::allocate(new_capacity);
if (data_) if (data_)
{ {
manager::construct(new_data, size_/* only construct needed size */); manager::construct_n(new_data, data_, size_/* only construct needed size */);
manager::copy_data(new_data, data_, size_);
/* destroy old memory, but not resize */ /* destroy old memory, but not resize */
destroy(); destroy();
} }
@ -176,9 +141,9 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity)
capacity_ = new_capacity; capacity_ = new_capacity;
} }
template<typename _Ty, typename _Alloc, typename _Manager> template<typename _Ty, typename _Alloc>
typename vector<_Ty, _Alloc, _Manager>::iterator typename vector<_Ty, _Alloc>::iterator
vector<_Ty, _Alloc, _Manager>::erase(const_iterator first, const_iterator last) vector<_Ty, _Alloc>::erase(const_iterator first, const_iterator last)
{ {
const auto off = first - begin(); const auto off = first - begin();
const auto count = last - first; const auto count = last - first;
@ -187,15 +152,15 @@ typename vector<_Ty, _Alloc, _Manager>::iterator
{ {
check_offset(off); 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 resize(size_ - count); // do destruction
} }
return begin() + off; return begin() + off;
} }
template<typename _Ty, typename _Alloc, typename _Manager> template<typename _Ty, typename _Alloc>
typename vector<_Ty, _Alloc, _Manager>::iterator typename vector<_Ty, _Alloc>::iterator
vector<_Ty, _Alloc, _Manager>::insert(const_iterator where, const _Ty& v) vector<_Ty, _Alloc>::insert(const_iterator where, const _Ty& v)
{ {
const auto off = where - begin(); const auto off = where - begin();
const auto insert_at = begin() + off; const auto insert_at = begin() + off;
@ -203,86 +168,9 @@ typename vector<_Ty, _Alloc, _Manager>::iterator
check_offset(off); check_offset(off);
resize(size_ + 1); 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; data_[off] = v;
return begin() + off; return begin() + off;
} }
namespace __vector_details } // namespace oc
{
//
// 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

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 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/core/win32/helper.h> #include <kiwano/platform/win32/helper.h> // win32::ThrowIfFailed
#include <kiwano-audio/audio-modules.h> #include <kiwano/core/Logger.h>
#include <kiwano-audio/libraries.h>
#include <kiwano-audio/AudioEngine.h> #include <kiwano-audio/AudioEngine.h>
namespace kiwano namespace kiwano
@ -38,13 +39,13 @@ namespace kiwano
void AudioEngine::SetupComponent() 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)) 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)) if (SUCCEEDED(hr))
@ -52,12 +53,12 @@ namespace kiwano
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_); hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
} }
ThrowIfFailed(hr); win32::ThrowIfFailed(hr);
} }
void AudioEngine::DestroyComponent() void AudioEngine::DestroyComponent()
{ {
// KGE_LOG(L"Destroying audio resources"); KGE_SYS_LOG(L"Destroying audio resources");
if (mastering_voice_) if (mastering_voice_)
{ {
@ -71,39 +72,54 @@ namespace kiwano
x_audio2_ = nullptr; 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!"); 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) win32::WarnIfFailed(hr);
{ return SUCCEEDED(hr);
(*voice)->DestroyVoice();
(*voice) = nullptr;
}
return x_audio2_->CreateSourceVoice(voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
} }
void AudioEngine::Open() void AudioEngine::Open()
{ {
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!"); KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
x_audio2_->StartEngine(); if (x_audio2_)
x_audio2_->StartEngine();
} }
void AudioEngine::Close() void AudioEngine::Close()
{ {
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!"); 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. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/common/singleton.hpp> #include <kiwano/core/common.h>
#include <kiwano/core/Component.h> #include <kiwano/core/Component.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano-audio/Transcoder.h> #include <kiwano-audio/Transcoder.h>
#include <kiwano-audio/Sound.h>
#include <xaudio2.h> #include <xaudio2.h>
namespace kiwano namespace kiwano
{ {
namespace audio namespace audio
{ {
/**
* \~chinese
* \defgroup Audio
*/
/**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API AudioEngine class KGE_API AudioEngine
: public Singleton<AudioEngine> : public Singleton<AudioEngine>
, public ComponentBase , public ComponentBase
{ {
KGE_DECLARE_SINGLETON(AudioEngine); friend Singleton<AudioEngine>;
public: public:
// 开启设备 /// \~chinese
/// @brief 开启音频设备
void Open(); void Open();
// 关闭设备 /// \~chinese
/// @brief 关闭音频设备
void Close(); void Close();
HRESULT CreateVoice( /// \~chinese
IXAudio2SourceVoice** voice, /// @brief 从解码器数据缓冲中创建音频对象
const Transcoder::Buffer& buffer bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
);
public: public:
void SetupComponent() override; void SetupComponent() override;
void DestroyComponent() override; void DestroyComponent() override;
protected: private:
AudioEngine(); AudioEngine();
~AudioEngine(); ~AudioEngine();
protected: private:
IXAudio2* x_audio2_; IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_; 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() Sound::~Sound()
{ {
Close(); Close();
@ -54,9 +42,9 @@ namespace kiwano
bool Sound::Load(String const& file_path) 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; return false;
} }
@ -65,22 +53,18 @@ namespace kiwano
Close(); Close();
} }
String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); String full_path = FileSystem::instance().GetFullPathForFile(file_path);
HRESULT hr = transcoder_.LoadMediaFile(full_path); HRESULT hr = transcoder_.LoadMediaFile(full_path);
if (FAILED(hr)) 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; return false;
} }
hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer()); if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer()))
if (FAILED(hr))
{ {
Close(); Close();
KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr);
return false; return false;
} }
@ -96,19 +80,15 @@ namespace kiwano
} }
HRESULT hr = transcoder_.LoadMediaResource(res); HRESULT hr = transcoder_.LoadMediaResource(res);
if (FAILED(hr)) 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; return false;
} }
hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer()); if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer()))
if (FAILED(hr))
{ {
Close(); Close();
KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr);
return false; return false;
} }
@ -116,11 +96,16 @@ namespace kiwano
return true; return true;
} }
bool Sound::IsValid() const
{
return voice_ != nullptr;
}
void Sound::Play(int loop_count) void Sound::Play(int loop_count)
{ {
if (!opened_) if (!opened_)
{ {
KGE_ERROR_LOG(L"Sound must be opened first!"); KGE_ERROR(L"Sound must be opened first!");
return; return;
} }
@ -151,7 +136,7 @@ namespace kiwano
if (FAILED(hr)) 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); playing_ = SUCCEEDED(hr);

View File

@ -19,9 +19,9 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/core/ObjectBase.h> #include <kiwano/core/ObjectBase.h>
#include <kiwano/core/Resource.h> #include <kiwano/core/Resource.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <kiwano-audio/Transcoder.h> #include <kiwano-audio/Transcoder.h>
#include <xaudio2.h> #include <xaudio2.h>
@ -29,68 +29,100 @@ namespace kiwano
{ {
namespace audio namespace audio
{ {
class AudioEngine;
KGE_DECLARE_SMART_PTR(Sound); KGE_DECLARE_SMART_PTR(Sound);
/**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Sound class KGE_API Sound
: public ObjectBase : public ObjectBase
{ {
friend class AudioEngine;
public: public:
Sound(); Sound();
Sound(
String const& file_path /* 本地音频文件 */
);
Sound(
Resource const& res /* 音乐资源 */
);
virtual ~Sound(); virtual ~Sound();
// 打开本地音频文件 /// \~chinese
bool Load( /// @brief 打开本地音频文件
String const& file_path /// @param res 本地音频文件路径
); bool Load(String const& file_path);
// 打开音乐资源 /// \~chinese
bool Load( /// @brief 打开音频资源
Resource const& res /* 音乐资源 */ /// @param res 音频资源
); bool Load(Resource const& res);
// 播放 /// \~chinese
void Play( /// @brief 是否有效
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */ bool IsValid() const;
);
// 暂停 /// \~chinese
/// @brief 播放
/// @param loop_count 播放循环次数,设置 -1 为循环播放
void Play(int loop_count = 0);
/// \~chinese
/// @brief 暂停
void Pause(); void Pause();
// 继续 /// \~chinese
/// @brief 继续
void Resume(); void Resume();
// 停止 /// \~chinese
/// @brief 停止
void Stop(); void Stop();
// 关闭并回收资源 /// \~chinese
/// @brief 关闭并销毁资源
void Close(); void Close();
// 是否正在播放 /// \~chinese
/// @brief 是否正在播放
bool IsPlaying() const; bool IsPlaying() const;
// 获取音量 /// \~chinese
/// @brief 获取音量
float GetVolume() const; float GetVolume() const;
// 设置音量 /// \~chinese
void SetVolume( /// @brief 设置音量
float volume /* 1 为原始音量, 大于 1 为放大音量, 0 为最小音量 */ /// @param volume 音量大小1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
); void SetVolume(float volume);
protected: private:
bool opened_; IXAudio2SourceVoice* GetXAudio2Voice() const;
bool playing_;
Transcoder transcoder_;
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
private:
bool opened_;
bool playing_;
Transcoder transcoder_;
IXAudio2SourceVoice* voice_; 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) void SoundPlayer::SetVolume(float volume)
{ {
volume_ = std::min(std::max(volume, -224.f), 224.f); 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_); pair.second->SetVolume(volume_);
} }
@ -126,7 +126,7 @@ namespace kiwano
void SoundPlayer::PauseAll() void SoundPlayer::PauseAll()
{ {
for (const auto& pair : sound_cache_) for (auto& pair : sound_cache_)
{ {
pair.second->Pause(); pair.second->Pause();
} }
@ -134,7 +134,7 @@ namespace kiwano
void SoundPlayer::ResumeAll() void SoundPlayer::ResumeAll()
{ {
for (const auto& pair : sound_cache_) for (auto& pair : sound_cache_)
{ {
pair.second->Resume(); pair.second->Resume();
} }
@ -142,7 +142,7 @@ namespace kiwano
void SoundPlayer::StopAll() void SoundPlayer::StopAll()
{ {
for (const auto& pair : sound_cache_) for (auto& pair : sound_cache_)
{ {
pair.second->Stop(); pair.second->Stop();
} }

View File

@ -19,7 +19,6 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/core/ObjectBase.h> #include <kiwano/core/ObjectBase.h>
#include <kiwano-audio/Sound.h> #include <kiwano-audio/Sound.h>
@ -29,76 +28,93 @@ namespace kiwano
{ {
KGE_DECLARE_SMART_PTR(SoundPlayer); KGE_DECLARE_SMART_PTR(SoundPlayer);
// 音乐播放器 /**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API SoundPlayer class KGE_API SoundPlayer
: protected ObjectBase : public ObjectBase
{ {
public: public:
SoundPlayer(); SoundPlayer();
~SoundPlayer(); ~SoundPlayer();
// 加载本地音频文件, 返回该资源的标识符 /// \~chinese
size_t Load( /// @brief 加载本地音频文件
String const& file_path /// @param file_path 本地音频文件路径
); /// @return 音频标识符
size_t Load(String const& file_path);
// 加载音乐资源, 返回该资源的标识符 /// \~chinese
size_t Load( /// @brief 加载音频资源
Resource const& res /* 音乐资源 */ /// @param res 音频资源
); /// @return 音频标识符
size_t Load(Resource const& res);
// 播放音乐 /// \~chinese
void Play( /// @brief 播放音频
size_t id, /* 标识符 */ /// @param id 音频标识符
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */ /// @param loop_count 播放循环次数,设置 -1 为循环播放
); void Play(size_t id, int loop_count = 0);
// 暂停音乐 /// \~chinese
void Pause( /// @brief 暂停音频
size_t id /* 标识符 */ /// @param id 音频标识符
); void Pause(size_t id);
// 继续播放音乐 /// \~chinese
void Resume( /// @brief 继续播放音频
size_t id /* 标识符 */ /// @param id 音频标识符
); void Resume(size_t id);
// 停止音乐 /// \~chinese
void Stop( /// @brief 停止音频
size_t id /* 标识符 */ /// @param id 音频标识符
); void Stop(size_t id);
// 获取音乐播放状态 /// \~chinese
bool IsPlaying( /// @brief 获取音频播放状态
size_t id /* 标识符 */ /// @param id 音频标识符
); bool IsPlaying(size_t id);
// 获取音量 /// \~chinese
/// @brief 获取音量
float GetVolume() const; float GetVolume() const;
// 设置音量 /// \~chinese
void SetVolume( /// @brief 设置音量
float volume /* 1.0 为原始音量 */ /// @param volume 音量大小1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
); void SetVolume(float volume);
// 暂停所有音乐 /// \~chinese
/// @brief 暂停所有音频
void PauseAll(); void PauseAll();
// 继续播放所有音乐 /// \~chinese
/// @brief 继续播放所有音频
void ResumeAll(); void ResumeAll();
// 停止所有音乐 /// \~chinese
/// @brief 停止所有音频
void StopAll(); void StopAll();
// 清除缓存 /// \~chinese
/// @brief 清除缓存
void ClearCache(); void ClearCache();
protected: private:
float volume_; float volume_;
using SoundMap = Map<size_t, SoundPtr>; using SoundMap = Map<size_t, SoundPtr>;
SoundMap sound_cache_; SoundMap sound_cache_;
}; };
/** @} */
} }
} }

View File

@ -23,12 +23,12 @@
#endif #endif
#include <kiwano/macros.h> #include <kiwano/macros.h>
#include <kiwano/common/string.hpp> #include <kiwano/core/common.h>
#include <kiwano/core/Resource.h> #include <kiwano/core/Resource.h>
#include <kiwano/core/Logger.h> #include <kiwano/core/Logger.h>
#include <kiwano/core/win32/ComPtr.hpp> #include <kiwano/platform/win32/ComPtr.hpp>
#include <kiwano/platform/modules.h> #include <kiwano/platform/win32/libraries.h>
#include <kiwano-audio/audio-modules.h> #include <kiwano-audio/libraries.h>
#include <kiwano-audio/Transcoder.h> #include <kiwano-audio/Transcoder.h>
namespace kiwano namespace kiwano
@ -76,7 +76,7 @@ namespace kiwano
ComPtr<IMFSourceReader> reader; ComPtr<IMFSourceReader> reader;
hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromURL( hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL(
file_path.c_str(), file_path.c_str(),
nullptr, nullptr,
&reader &reader
@ -101,25 +101,25 @@ namespace kiwano
Resource::Data data = res.GetData(); Resource::Data data = res.GetData();
if (!data) { return E_FAIL; } 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<const BYTE*>(data.buffer),
static_cast<uint32_t>(data.size) static_cast<uint32_t>(data.size)
); );
if (stream == nullptr) if (stream == nullptr)
{ {
KGE_ERROR_LOG(L"SHCreateMemStream failed"); KGE_ERROR(L"SHCreateMemStream failed");
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = modules::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream); hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromByteStream( hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(
byte_stream.get(), byte_stream.get(),
nullptr, nullptr,
&reader &reader
@ -142,7 +142,7 @@ namespace kiwano
ComPtr<IMFMediaType> partial_type; ComPtr<IMFMediaType> partial_type;
ComPtr<IMFMediaType> uncompressed_type; ComPtr<IMFMediaType> uncompressed_type;
hr = modules::MediaFoundation::Get().MFCreateMediaType(&partial_type); hr = dlls::MediaFoundation::Get().MFCreateMediaType(&partial_type);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -186,7 +186,7 @@ namespace kiwano
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
uint32_t size = 0; uint32_t size = 0;
hr = modules::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType( hr = dlls::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType(
uncompressed_type.get(), uncompressed_type.get(),
&wave_format_, &wave_format_,
&size, &size,
@ -225,7 +225,7 @@ namespace kiwano
if (data == nullptr) if (data == nullptr)
{ {
KGE_ERROR_LOG(L"Low memory"); KGE_ERROR(L"Low memory");
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
} }
else else

View File

@ -28,41 +28,64 @@ namespace kiwano
{ {
namespace audio namespace audio
{ {
class Sound;
/**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Transcoder class KGE_API Transcoder
{ {
friend class Sound;
public: public:
/**
* \~chinese
* @brief
*/
struct Buffer struct Buffer
{ {
BYTE* data; BYTE* data; ///< 音频数据
uint32_t size; uint32_t size; ///< 音频数据大小
const WAVEFORMATEX* format; const WAVEFORMATEX* format; ///< 音频数据格式
}; };
Transcoder(); Transcoder();
~Transcoder(); ~Transcoder();
/// \~chinese
/// @brief 获取数据缓冲
Buffer GetBuffer() const; Buffer GetBuffer() const;
/// \~chinese
/// @brief 清空数据缓冲
void ClearBuffer(); void ClearBuffer();
HRESULT LoadMediaFile( private:
String const& file_path /// \~chinese
); /// @brief 解码本地音频文件
HRESULT LoadMediaFile(String const& file_path);
HRESULT LoadMediaResource( /// \~chinese
Resource const& res /// @brief 解码音频资源
); HRESULT LoadMediaResource(Resource const& res);
HRESULT ReadSource( /// \~chinese
IMFSourceReader* reader /// @brief 读取音频源数据
); HRESULT ReadSource(IMFSourceReader* reader);
private: private:
BYTE* wave_data_; BYTE* wave_data_;
uint32_t wave_size_; uint32_t wave_size_;
WAVEFORMATEX* wave_format_; WAVEFORMATEX* wave_format_;
}; };
/** @} */
} }
} }

View File

@ -19,13 +19,13 @@
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/core/Logger.h> #include <kiwano/core/Logger.h>
#include <kiwano-audio/audio-modules.h> #include <kiwano-audio/libraries.h>
namespace kiwano namespace kiwano
{ {
namespace audio namespace audio
{ {
namespace modules namespace dlls
{ {
XAudio2::XAudio2() XAudio2::XAudio2()
: xaudio2() : xaudio2()
@ -33,9 +33,9 @@ namespace kiwano
{ {
const auto xaudio2_dll_names = const auto xaudio2_dll_names =
{ {
L"xaudio2_9.dll", // for Windows 10 "xaudio2_9.dll", // for Windows 10
L"xaudio2_8.dll", // for Windows 8 "xaudio2_8.dll", // for Windows 8
L"xaudio2_7.dll" // for DirectX SDK "xaudio2_7.dll" // for DirectX SDK
}; };
for (const auto& name : xaudio2_dll_names) for (const auto& name : xaudio2_dll_names)
@ -48,11 +48,11 @@ namespace kiwano
if (xaudio2.IsValid()) if (xaudio2.IsValid())
{ {
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>(L"XAudio2Create"); XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("XAudio2Create");
} }
else else
{ {
KGE_ERROR_LOG(L"Load xaudio2.dll failed"); KGE_ERROR(L"Load xaudio2.dll failed");
throw std::runtime_error("Load xaudio2.dll failed"); throw std::runtime_error("Load xaudio2.dll failed");
} }
} }
@ -68,28 +68,28 @@ namespace kiwano
, MFCreateSourceReaderFromByteStream(nullptr) , MFCreateSourceReaderFromByteStream(nullptr)
, MFCreateMFByteStreamOnStream(nullptr) , MFCreateMFByteStreamOnStream(nullptr)
{ {
if (mfplat.Load(L"Mfplat.dll")) if (mfplat.Load("Mfplat.dll"))
{ {
MFStartup = mfplat.GetProcess<PFN_MFStartup>(L"MFStartup"); MFStartup = mfplat.GetProcess<PFN_MFStartup>("MFStartup");
MFShutdown = mfplat.GetProcess<PFN_MFShutdown>(L"MFShutdown"); MFShutdown = mfplat.GetProcess<PFN_MFShutdown>("MFShutdown");
MFCreateMediaType = mfplat.GetProcess<PFN_MFCreateMediaType>(L"MFCreateMediaType"); MFCreateMediaType = mfplat.GetProcess<PFN_MFCreateMediaType>("MFCreateMediaType");
MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess<PFN_MFCreateWaveFormatExFromMFMediaType>(L"MFCreateWaveFormatExFromMFMediaType"); MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess<PFN_MFCreateWaveFormatExFromMFMediaType>("MFCreateWaveFormatExFromMFMediaType");
MFCreateMFByteStreamOnStream = mfplat.GetProcess<PFN_MFCreateMFByteStreamOnStream>(L"MFCreateMFByteStreamOnStream"); MFCreateMFByteStreamOnStream = mfplat.GetProcess<PFN_MFCreateMFByteStreamOnStream>("MFCreateMFByteStreamOnStream");
} }
else else
{ {
KGE_LOG(L"Load Mfplat.dll failed"); KGE_ERROR(L"Load Mfplat.dll failed");
throw std::runtime_error("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"); MFCreateSourceReaderFromURL = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromURL>("MFCreateSourceReaderFromURL");
MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>(L"MFCreateSourceReaderFromByteStream"); MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>("MFCreateSourceReaderFromByteStream");
} }
else else
{ {
KGE_LOG(L"Load Mfreadwrite.dll failed"); KGE_ERROR(L"Load Mfreadwrite.dll failed");
throw std::runtime_error("Load Mfreadwrite.dll failed"); throw std::runtime_error("Load Mfreadwrite.dll failed");
} }
} }

View File

@ -25,11 +25,13 @@
#include <mfidl.h> #include <mfidl.h>
#include <mfreadwrite.h> #include <mfreadwrite.h>
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
namespace kiwano namespace kiwano
{ {
namespace audio namespace audio
{ {
namespace modules namespace dlls
{ {
class KGE_API XAudio2 class KGE_API XAudio2
{ {
@ -93,3 +95,5 @@ namespace kiwano
} }
} }
} }
#endif

View File

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

View File

@ -27,8 +27,14 @@ namespace kiwano
{ {
KGE_DECLARE_SMART_PTR(ImGuiLayer); KGE_DECLARE_SMART_PTR(ImGuiLayer);
/// \~chinese
/// @brief ImGui管道
using ImGuiPipeline = Function<void()>; using ImGuiPipeline = Function<void()>;
/**
* \~chinese
* @brief ImGui图层
*/
class ImGuiLayer class ImGuiLayer
: public Layer : public Layer
{ {
@ -37,24 +43,26 @@ namespace kiwano
virtual ~ImGuiLayer(); virtual ~ImGuiLayer();
// Ìí¼Ó ImGui ÔªËØ /// \~chinese
void AddItem( /// @brief 添加 ImGui 元素
ImGuiPipeline const& item, /// @param item 管道
String const& name /// @param name 元素名称
); void AddItem(ImGuiPipeline const& item, String const& name);
// ÒÆ³ý ImGui ÔªËØ /// \~chinese
void RemoveItem( /// @brief 移除 ImGui 元素
String const& name /// @param name 元素名称
); void RemoveItem(String const& name);
// 移除所有元素 // 移除所有元素
/// \~chinese
/// @brief 移除所有元素
void RemoveAllItems(); void RemoveAllItems();
public: public:
void OnRender(RenderTarget* rt) override; void OnRender(RenderTarget* rt) override;
protected: private:
Map<String, ImGuiPipeline> pipelines_; Map<String, ImGuiPipeline> pipelines_;
}; };
} }

View File

@ -1,8 +1,6 @@
// Copyright (C) 2019 Nomango // Copyright (C) 2019 Nomango
#include <kiwano/common/common.h> #include <kiwano/core/common.h>
#include <kiwano/common/Function.hpp>
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/platform/Window.h> #include <kiwano/platform/Window.h>
#include <kiwano/platform/Input.h> #include <kiwano/platform/Input.h>
#include <kiwano/renderer/Renderer.h> #include <kiwano/renderer/Renderer.h>
@ -45,9 +43,9 @@ namespace kiwano
//ImGui::StyleColorsClassic(); //ImGui::StyleColorsClassic();
// Setup Platform/Renderer bindings // 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() void ImGuiModule::DestroyComponent()
@ -64,9 +62,9 @@ namespace kiwano
io.DeltaTime = dt.Seconds(); io.DeltaTime = dt.Seconds();
// Read keyboard modifiers inputs // Read keyboard modifiers inputs
io.KeyCtrl = Input::GetInstance()->IsDown(KeyCode::Ctrl); io.KeyCtrl = Input::instance().IsDown(KeyCode::Ctrl);
io.KeyShift = Input::GetInstance()->IsDown(KeyCode::Shift); io.KeyShift = Input::instance().IsDown(KeyCode::Shift);
io.KeyAlt = Input::GetInstance()->IsDown(KeyCode::Alt); io.KeyAlt = Input::instance().IsDown(KeyCode::Alt);
io.KeySuper = false; io.KeySuper = false;
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. // 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_Y] = KeyCode::Y;
io.KeyMap[ImGuiKey_Z] = KeyCode::Z; io.KeyMap[ImGuiKey_Z] = KeyCode::Z;
ImGui_Impl_Init(Renderer::GetInstance()); ImGui_Impl_Init(&Renderer::instance());
} }
void ImGuiModule::BeforeRender() void ImGuiModule::BeforeRender()
@ -213,7 +211,7 @@ namespace kiwano
KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!");
// Setup display size (every frame to accommodate for window resizing) // 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); io.DisplaySize = ImVec2(display_size.x, display_size.y);
ImGui::NewFrame(); ImGui::NewFrame();
@ -238,7 +236,7 @@ namespace kiwano
::SetCursorPos(pos.x, pos.y); ::SetCursorPos(pos.x, pos.y);
} }
Point pos = Input::GetInstance()->GetMousePos(); Point pos = Input::instance().GetMousePos();
io.MousePos = ImVec2(pos.x, pos.y); io.MousePos = ImVec2(pos.x, pos.y);
} }
@ -260,7 +258,7 @@ namespace kiwano
case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break; case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break;
} }
Window::GetInstance()->SetCursor(cursor); Window::instance().SetCursor(cursor);
} }
void ImGuiModule::UpdateGamepads() void ImGuiModule::UpdateGamepads()
{ {

View File

@ -19,27 +19,24 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/core/common.h>
#include <kiwano/core/Component.h> #include <kiwano/core/Component.h>
#include <kiwano/common/singleton.hpp>
namespace kiwano namespace kiwano
{ {
namespace imgui namespace imgui
{ {
/**
* \~chinese
* @brief ImGuiÄ£¿é
*/
class ImGuiModule class ImGuiModule
: public Singleton<ImGuiModule> : public Singleton<ImGuiModule>
, public RenderComponent , public RenderComponent
, public UpdateComponent , public UpdateComponent
, public EventComponent , public EventComponent
{ {
KGE_DECLARE_SINGLETON(ImGuiModule); friend Singleton<ImGuiModule>;
private:
void Init(HWND hwnd);
void NewFrame();
void Render();
public: public:
ImGuiModule(); ImGuiModule();
@ -48,14 +45,21 @@ namespace kiwano
void DestroyComponent() override; void DestroyComponent() override;
void OnUpdate(Duration dt) override;
void BeforeRender() override; void BeforeRender() override;
void AfterRender() override; void AfterRender() override;
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) 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 UpdateMousePos();
void UpdateMouseCursor(); void UpdateMouseCursor();

View File

@ -2,6 +2,8 @@
#pragma once #pragma once
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
#if !defined(KGE_USE_DIRECTX10) #if !defined(KGE_USE_DIRECTX10)
#include <kiwano-imgui/imgui_impl_dx11.h> #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(); } inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX10_CreateDeviceObjects(); }
#endif #endif
#endif

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include <3rd-party/imgui/imgui.h> #include <3rd-party/imgui/imgui.h>
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
struct ID3D10Device; struct ID3D10Device;
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device); 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. // Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
#endif

View File

@ -1,6 +1,5 @@
// dear imgui: Renderer for Kiwano (DirectX11) // dear imgui: Renderer for Kiwano (DirectX11)
#include <kiwano/core/win32/helper.h>
#include <kiwano-imgui/imgui_impl_dx11.h> #include <kiwano-imgui/imgui_impl_dx11.h>
// DirectX // DirectX
@ -259,9 +258,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
subResource.pSysMem = pixels; subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4; subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0; subResource.SysMemSlicePitch = 0;
kiwano::ThrowIfFailed( g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture)
);
if (pTexture) if (pTexture)
{ {
@ -272,9 +269,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Texture2D.MostDetailedMip = 0;
kiwano::ThrowIfFailed( g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView)
);
pTexture->Release(); pTexture->Release();
} }

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include <3rd-party/imgui/imgui.h> #include <3rd-party/imgui/imgui.h>
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
struct ID3D11Device; struct ID3D11Device;
struct ID3D11DeviceContext; 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. // Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
#endif

View File

@ -24,4 +24,4 @@
#include <kiwano-imgui/ImGuiModule.h> #include <kiwano-imgui/ImGuiModule.h>
// ImGui // 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) 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; uint32_t total = size * nmemb;
// add data to the end of recv_buffer // add data to the end of recv_buffer
@ -46,10 +46,10 @@ namespace
return total; 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; std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
common::string result; ByteString result;
try try
{ {
@ -58,15 +58,15 @@ namespace
catch (std::range_error&) catch (std::range_error&)
{ {
// bad conversion // bad conversion
result = wide_to_string(str); result = WideToMultiByte(str);
} }
return result; 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; oc::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
common::wstring result; String result;
try try
{ {
@ -75,7 +75,7 @@ namespace
catch (std::range_error&) catch (std::range_error&)
{ {
// bad conversion // bad conversion
result = string_to_wide(str); result = MultiByteToWide(str);
} }
return result; 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)) if (!SetOption(CURLOPT_ERRORBUFFER, error_buffer))
return false; return false;
@ -170,11 +170,11 @@ namespace
public: public:
static inline bool GetRequest( static inline bool GetRequest(
HttpClient* client, HttpClient* client,
Vector<common::string> const& headers, Vector<ByteString> const& headers,
common::string const& url, ByteString const& url,
long* response_code, long* response_code,
common::string* response_data, ByteString* response_data,
common::string* response_header, ByteString* response_header,
char* error_buffer) char* error_buffer)
{ {
Curl curl; Curl curl;
@ -185,12 +185,12 @@ namespace
static inline bool PostRequest( static inline bool PostRequest(
HttpClient* client, HttpClient* client,
Vector<common::string> const& headers, Vector<ByteString> const& headers,
common::string const& url, ByteString const& url,
common::string const& request_data, ByteString const& request_data,
long* response_code, long* response_code,
common::string* response_data, ByteString* response_data,
common::string* response_header, ByteString* response_header,
char* error_buffer) char* error_buffer)
{ {
Curl curl; Curl curl;
@ -203,12 +203,12 @@ namespace
static inline bool PutRequest( static inline bool PutRequest(
HttpClient* client, HttpClient* client,
Vector<common::string> const& headers, Vector<ByteString> const& headers,
common::string const& url, ByteString const& url,
common::string const& request_data, ByteString const& request_data,
long* response_code, long* response_code,
common::string* response_data, ByteString* response_data,
common::string* response_header, ByteString* response_header,
char* error_buffer) char* error_buffer)
{ {
Curl curl; Curl curl;
@ -221,11 +221,11 @@ namespace
static inline bool DeleteRequest( static inline bool DeleteRequest(
HttpClient* client, HttpClient* client,
Vector<common::string> const& headers, Vector<ByteString> const& headers,
common::string const& url, ByteString const& url,
long* response_code, long* response_code,
common::string* response_data, ByteString* response_data,
common::string* response_header, ByteString* response_header,
char* error_buffer) char* error_buffer)
{ {
Curl curl; Curl curl;
@ -307,13 +307,13 @@ namespace kiwano
bool ok = false; bool ok = false;
long response_code = 0; long response_code = 0;
char error_message[256] = { 0 }; char error_message[256] = { 0 };
common::string response_header; ByteString response_header;
common::string response_data; ByteString response_data;
common::string url = convert_to_utf8(request->GetUrl()); ByteString url = convert_to_utf8(request->GetUrl());
common::string data = convert_to_utf8(request->GetData()); ByteString data = convert_to_utf8(request->GetData());
Vector<common::string> headers; Vector<ByteString> headers;
headers.reserve(request->GetHeaders().size()); headers.reserve(request->GetHeaders().size());
for (const auto& pair : request->GetHeaders()) 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); ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
break; break;
default: 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; return;
} }
response->SetResponseCode(response_code); response->SetResponseCode(response_code);
response->SetHeader(string_to_wide(response_header)); response->SetHeader(MultiByteToWide(response_header));
response->SetData(convert_from_utf8(response_data)); response->SetData(convert_from_utf8(response_data));
if (!ok) if (!ok)
{ {
response->SetSucceed(false); response->SetSucceed(false);
response->SetError(string_to_wide(error_message)); response->SetError(MultiByteToWide(error_message));
} }
else else
{ {

View File

@ -19,8 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/common/common.h> #include <kiwano/core/common.h>
#include <kiwano/common/singleton.hpp>
#include <kiwano/core/Component.h> #include <kiwano/core/Component.h>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
@ -29,25 +28,55 @@ namespace kiwano
{ {
namespace network namespace network
{ {
/**
* \~chinese
* \defgroup Network
*/
/**
* \addtogroup Network
* @{
*/
/**
* \~chinese
* @brief HTTP客户端
*/
class KGE_API HttpClient class KGE_API HttpClient
: public Singleton<HttpClient> : public Singleton<HttpClient>
, public ComponentBase , public ComponentBase
{ {
KGE_DECLARE_SINGLETON(HttpClient); friend Singleton<HttpClient>;
public: public:
/// \~chinese
/// @brief 发送HTTP请求
/// @param[in] request HTTP请求
/// @details 发送请求后,无论结束或失败都将调用请求的响应回调函数
void Send(HttpRequestPtr request); void Send(HttpRequestPtr request);
/// \~chinese
/// @brief 设置连接超时时长
void SetTimeoutForConnect(Duration timeout); void SetTimeoutForConnect(Duration timeout);
/// \~chinese
/// @brief 获取连接超时时长
Duration GetTimeoutForConnect() const; Duration GetTimeoutForConnect() const;
/// \~chinese
/// @brief 设置读取超时时长
void SetTimeoutForRead(Duration timeout); void SetTimeoutForRead(Duration timeout);
/// \~chinese
/// @brief 获取读取超时时长
Duration GetTimeoutForRead() const; Duration GetTimeoutForRead() const;
/// \~chinese
/// @brief 设置SSL证书地址
void SetSSLVerification(String const& root_certificate_path); void SetSSLVerification(String const& root_certificate_path);
/// \~chinese
/// @brief 获取SSL证书地址
String const& GetSSLVerification() const; String const& GetSSLVerification() const;
public: public:
@ -60,10 +89,7 @@ namespace kiwano
void NetworkThread(); void NetworkThread();
void Perform( void Perform(HttpRequestPtr request, HttpResponsePtr response);
HttpRequestPtr request,
HttpResponsePtr response
);
void DispatchResponseCallback(); void DispatchResponseCallback();
@ -82,6 +108,8 @@ namespace kiwano
std::condition_variable_any sleep_condition_; std::condition_variable_any sleep_condition_;
}; };
/** @} */
inline void HttpClient::SetTimeoutForConnect(Duration timeout) inline void HttpClient::SetTimeoutForConnect(Duration timeout)
{ {

View File

@ -19,8 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <kiwano/common/function.hpp> #include <kiwano/core/common.h>
#include <kiwano/common/basic_json.hpp>
#include <kiwano/core/ObjectBase.h> #include <kiwano/core/ObjectBase.h>
#include <kiwano/core/SmartPtr.hpp> #include <kiwano/core/SmartPtr.hpp>
@ -32,49 +31,91 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(HttpRequest); KGE_DECLARE_SMART_PTR(HttpRequest);
/**
* \addtogroup Network
* @{
*/
/**
* \~chinese
* @brief HTTP请求
*/
class KGE_API HttpRequest class KGE_API HttpRequest
: public ObjectBase : public ObjectBase
{ {
public: public:
using ResponseCallback = Function<void(HttpRequest*, HttpResponse*)>; /// \~chinese
/// @brief 响应回调函数
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
/// \~chinese
/// @brief 请求类型
enum class Type enum class Type
{ {
Unknown, Unknown, ///< 未知
Get, Get, ///< HTTP GET请求
Post, Post, ///< HTTP POST请求
Put, Put, ///< HTTP PUT请求
Delete Delete ///< HTTP DELETE请求
}; };
HttpRequest(); HttpRequest();
HttpRequest(Type type); HttpRequest(Type type);
// 请求地址 /// \~chinese
/// @brief 设置请求地址
void SetUrl(String const& url); 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; String const& GetUrl() const;
// 请求类型 /// \~chinese
void SetType(Type type); /// @brief 获取请求类型
Type GetType() const; Type GetType() const;
// 请求数据 /// \~chinese
void SetData(String const& data); /// @brief 获取请求数据
void SetJsonData(Json const& json);
String const& GetData() const; String const& GetData() const;
// 请求头 /// \~chinese
void SetHeaders(Map<String, String> const& headers); /// @brief 获取HTTP头
void SetHeader(String const& field, String const& content);
Map<String, String>& GetHeaders(); Map<String, String>& GetHeaders();
/// \~chinese
/// @brief 获取HTTP头
String const& GetHeader(String const& header) const; String const& GetHeader(String const& header) const;
// 响应回调 /// \~chinese
void SetResponseCallback(ResponseCallback const& callback); /// @brief 获取响应回调函数
ResponseCallback const& GetResponseCallback() const; ResponseCallback const& GetResponseCallback() const;
protected: private:
Type type_; Type type_;
String url_; String url_;
String data_; String data_;
@ -82,6 +123,8 @@ namespace kiwano
ResponseCallback response_cb_; ResponseCallback response_cb_;
}; };
/** @} */
inline HttpRequest::HttpRequest() : type_(Type::Unknown) {} inline HttpRequest::HttpRequest() : type_(Type::Unknown) {}
inline HttpRequest::HttpRequest(Type type) : type_(type) {} inline HttpRequest::HttpRequest(Type type) : type_(type) {}

View File

@ -27,36 +27,66 @@ namespace kiwano
{ {
KGE_DECLARE_SMART_PTR(HttpResponse); KGE_DECLARE_SMART_PTR(HttpResponse);
/**
* \addtogroup Network
* @{
*/
/**
* \~chinese
* @brief HTTP响应
*/
class KGE_API HttpResponse class KGE_API HttpResponse
: public ObjectBase : public ObjectBase
{ {
public: public:
HttpResponse(HttpRequestPtr request); HttpResponse(HttpRequestPtr request);
// 获取请求 /// \~chinese
/// @brief 获取对应的HTTP请求
HttpRequestPtr GetRequest() const; HttpRequestPtr GetRequest() const;
// 响应状态 /// \~chinese
/// @brief 获取响应状态
bool IsSucceed() const; 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); void SetSucceed(bool succeed);
// 响应状态码 /// \~chinese
long GetResponseCode() const; /// @brief 设置HTTP状态码
void SetResponseCode(long response_code); void SetResponseCode(long response_code);
// 响应头 /// \~chinese
String GetHeader() const; /// @brief 设置响应头
void SetHeader(String const& response_header); void SetHeader(String const& response_header);
// 响应数据 /// \~chinese
String const& GetData() const; /// @brief 设置响应数据
void SetData(String const& response_data); void SetData(String const& response_data);
// 错误信息 /// \~chinese
String const& GetError() const; /// @brief 设置错误信息
void SetError(String const& error_buffer); void SetError(String const& error_buffer);
protected: private:
bool succeed_; bool succeed_;
long response_code_; long response_code_;
HttpRequestPtr request_; HttpRequestPtr request_;
@ -66,6 +96,8 @@ namespace kiwano
String error_buffer_; String error_buffer_;
}; };
/** @} */
inline HttpResponse::HttpResponse(HttpRequestPtr request) : request_(request), succeed_(false), response_code_(0) {} inline HttpResponse::HttpResponse(HttpRequestPtr request) : request_(request), succeed_(false), response_code_(0) {}
inline HttpRequestPtr HttpResponse::GetRequest() const { return request_; } inline HttpRequestPtr HttpResponse::GetRequest() const { return request_; }

View File

@ -104,8 +104,7 @@ namespace kiwano
{ {
if (fixture.GetB2Fixture()) if (fixture.GetB2Fixture())
{ {
b2Fixture* ptr = const_cast<b2Fixture*>(fixture.GetB2Fixture()); body_->DestroyFixture(fixture.GetB2Fixture());
body_->DestroyFixture(ptr);
} }
} }
@ -254,7 +253,7 @@ namespace kiwano
void Body::Destroy() void Body::Destroy()
{ {
if (world_) if (world_ && body_)
{ {
world_->RemoveBody(this); world_->RemoveBody(this);
} }

View File

@ -22,7 +22,7 @@
#include <kiwano-physics/helper.h> #include <kiwano-physics/helper.h>
#include <kiwano-physics/Shape.h> #include <kiwano-physics/Shape.h>
#include <kiwano-physics/Fixture.h> #include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Contact.h> #include <kiwano-physics/ContactEdge.h>
namespace kiwano namespace kiwano
{ {
@ -30,141 +30,284 @@ namespace kiwano
{ {
class World; class World;
// 膠竟
KGE_DECLARE_SMART_PTR(Body); KGE_DECLARE_SMART_PTR(Body);
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物体
class KGE_API Body class KGE_API Body
: public virtual RefCounter : public virtual RefCounter
{ {
public: public:
/// \~chinese
/// @brief 物体类型
enum class Type enum class Type
{ {
Static = 0, Static = 0, ///< 静态物体
Kinematic, Kinematic, ///< 动力学物体
Dynamic, Dynamic, ///< 动态物体
}; };
Body(); Body();
Body(b2Body* body, Actor* actor); Body(b2Body* body, Actor* actor);
Body(World* world, Actor* actor); Body(World* world, Actor* actor);
Body(World* world, ActorPtr actor) : Body(world, actor.get()) {} Body(World* world, ActorPtr actor);
virtual ~Body(); virtual ~Body();
// 놓迦뺏 /// \~chinese
/// @brief 初始化
/// @param[in] world 物理世界
/// @param[in] actor 绑定的角色
void Init(World* world, Actor* actor); void Init(World* world, Actor* actor);
// 警속셸야 /// \~chinese
/// @brief 添加夹具
/// @param shape 物体形状
/// @param density 物体密度
Fixture AddFixture(Shape* shape, const Fixture::Param& param); Fixture AddFixture(Shape* shape, const Fixture::Param& param);
// 警속近榴 /// \~chinese
/// @brief 添加圆形夹具
/// @param radius 圆形半径
/// @param density 物体密度
Fixture AddCircleShape(float radius, float density = 0.f); Fixture AddCircleShape(float radius, float density = 0.f);
/// \~chinese
/// @brief 添加盒形夹具
/// @param size 盒大小
/// @param density 物体密度
Fixture AddBoxShape(Vec2 const& size, float density = 0.f); 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); 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); 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 AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
// 삿혤셸야 /// \~chinese
Fixture GetFixtureList() const { KGE_ASSERT(body_); return Fixture(body_->GetFixtureList()); } /// @brief 获取夹具列表
FixtureList GetFixtureList() const;
// 盧뇜셸야 /// \~chinese
/// @brief 移除夹具
void RemoveFixture(Fixture const& fixture); void RemoveFixture(Fixture const& fixture);
// 삿혤쌈뇰긋 /// \~chinese
ContactEdge GetContactList() const { KGE_ASSERT(body_); ContactEdge(body_->GetContactList()); } /// @brief 获取接触边列表
ContactEdgeList GetContactList() const;
// 잚깎쯤 /// \~chinese
uint16_t GetCategoryBits() const { return category_bits_; } /// @brief 获取类别码
uint16_t GetCategoryBits() const;
/// \~chinese
/// @brief 设置类别码
void SetCategoryBits(uint16_t category_bits); void SetCategoryBits(uint16_t category_bits);
// 툭旒拿쯤 /// \~chinese
uint16_t GetMaskBits() const { return mask_bits_; } /// @brief 获取碰撞掩码
uint16_t GetMaskBits() const;
/// \~chinese
/// @brief 设置碰撞掩码
void SetMaskBits(uint16_t mask_bits); void SetMaskBits(uint16_t mask_bits);
// 莉乞多 /// \~chinese
int16_t GetGroupIndex() const { return group_index_; } /// @brief 获取组索引
int16_t GetGroupIndex() const;
/// \~chinese
/// @brief 设置组索引
void SetGroupIndex(int16_t index); void SetGroupIndex(int16_t index);
// 旗瘻실똑 /// \~chinese
float GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); } /// @brief 获取旋转角度
void SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); } float GetBodyRotation() const;
// 貫零 /// \~chinese
/// @brief 设置旋转角度
void SetBodyRotation(float angle);
/// \~chinese
/// @brief 获取物体位置
Point GetBodyPosition() const; 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); void SetBodyTransform(Point const& pos, float angle);
// 醴좆 /// \~chinese
float GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); } /// @brief 获取质量 [kg]
float GetMass() const;
// 발昑 /// \~chinese
float GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); } /// @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; 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); void SetMassData(float mass, Point const& center, float inertia);
/// \~chinese
/// @brief 重置质量数据
void ResetMassData(); void ResetMassData();
// 麟깃瘻뻣 /// \~chinese
/// @brief 获取世界坐标系上的点在物体上的位置
Point GetLocalPoint(Point const& world) const; Point GetLocalPoint(Point const& world) const;
/// \~chinese
/// @brief 获取物体上的点在世界坐标系的位置
Point GetWorldPoint(Point const& local) const; Point GetWorldPoint(Point const& local) const;
// 醴懃麟깃 /// \~chinese
/// @brief 获取物体质心相对于物体的位置
Point GetLocalCenter() const; Point GetLocalCenter() const;
/// \~chinese
/// @brief 获取物体质心位置
Point GetWorldCenter() const; Point GetWorldCenter() const;
// 膠竟잚謹 /// \~chinese
Type GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); } /// @brief 获取物体类型
void SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast<b2BodyType>(type)); } Type GetType() const;
// 路제凜綾 /// \~chinese
float GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); } /// @brief 设置物体类型
void SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); } 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); 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 ApplyForceToCenter(Vec2 const& force, bool wake = true);
// 嘉속큉앤 /// \~chinese
void ApplyTorque(float torque, bool wake = true); /// @brief 施加扭矩
/// @param torque 扭矩
/// @param wake 是否唤醒物体
void ApplyTorque(float torque, bool wake = false);
// 미땍旗瘻 /// \~chinese
bool IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); } /// @brief 旋转角度是否固定
void SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); } bool IsIgnoreRotation() const;
// 綾뎐 /// \~chinese
bool IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); } /// @brief 设置是否固定旋转角度
void SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); } void SetIgnoreRotation(bool flag);
// 金추 /// \~chinese
bool IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); } /// @brief 是否是子弹物体
void SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); } bool IsBullet() const;
bool IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); }
void SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); }
// 삶땡榴檄 /// \~chinese
bool IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); } /// @brief 设置物体是否是子弹物体
void SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); } void SetBullet(bool flag);
Actor* GetActor() const { return actor_; } /// \~chinese
void SetActor(Actor* actor) { actor_ = actor; } /// @brief 是否处于唤醒状态
bool IsAwake() const;
b2Body* GetB2Body() { return body_; } /// \~chinese
const b2Body* GetB2Body() const { return body_; } /// @brief 设置唤醒状态
void SetB2Body(b2Body* body); void SetAwake(bool flag);
World* GetWorld() { return world_; } /// \~chinese
const World* GetWorld() const { return world_; } /// @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(); void UpdateActor();
/// \~chinese
/// @brief 将角色信息更新到物体
void UpdateFromActor(); void UpdateFromActor();
protected: b2Body* GetB2Body() const;
void SetB2Body(b2Body* body);
private:
/// \~chinese
/// @brief 销毁物体
void UpdateFixtureFilter(b2Fixture* fixture); void UpdateFixtureFilter(b2Fixture* fixture);
protected: /// \~chinese
/// @brief 销毁物体
void Destroy();
private:
Actor* actor_; Actor* actor_;
World* world_; World* world_;
b2Body* body_; b2Body* body_;
@ -173,5 +316,65 @@ namespace kiwano
uint16_t mask_bits_; uint16_t mask_bits_;
int16_t group_index_; 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); SetB2Contact(contact);
} }
Contact Contact::GetNext() Fixture Contact::GetFixtureA() const
{
KGE_ASSERT(contact_);
return Contact(contact_->GetNext());
}
const Contact Contact::GetNext() const
{
KGE_ASSERT(contact_);
return Contact(contact_->GetNext());
}
Fixture Contact::GetFixtureA()
{ {
KGE_ASSERT(contact_); KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureA()); return Fixture(contact_->GetFixtureA());
} }
const Fixture Contact::GetFixtureA() const Fixture Contact::GetFixtureB() const
{
KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureA());
}
Fixture Contact::GetFixtureB()
{ {
KGE_ASSERT(contact_); KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureB()); return Fixture(contact_->GetFixtureB());
} }
const Fixture Contact::GetFixtureB() const Body* Contact::GetBodyA() const
{ {
KGE_ASSERT(contact_); return GetFixtureA().GetBody();
return Fixture(contact_->GetFixtureB()); }
Body* Contact::GetBodyB() const
{
return GetFixtureB().GetBody();
} }
void Contact::SetTangentSpeed(float speed) void Contact::SetTangentSpeed(float speed)
@ -100,17 +86,5 @@ namespace kiwano
return world->World2Stage(contact_->GetTangentSpeed()); 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; class Body;
// 接触 /**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物理接触
class KGE_API Contact class KGE_API Contact
{ {
public: public:
Contact(); Contact();
Contact(b2Contact* contact); Contact(b2Contact* contact);
// 是否是接触
bool IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); }
// 启用或禁用 (仅作用于一个时间步) /// \~chinese
void SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); } /// @brief 是否有效
bool IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); } bool IsValid() const;
// 获取下一接触 /// \~chinese
Contact GetNext(); /// @brief 是否是接触
const Contact GetNext() const; bool IsTouching() const;
// 夹具 A /// \~chinese
Fixture GetFixtureA(); /// @brief 启用或禁用 (仅作用于一个时间步)
const Fixture GetFixtureA() const; void SetEnabled(bool flag);
// 夹具 B /// \~chinese
Fixture GetFixtureB(); /// @brief 是否启用
const Fixture GetFixtureB() const; bool IsEnabled() const;
// 摩擦 /// \~chinese
void SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); } /// @brief 获取物体A的夹具
float GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); } Fixture GetFixtureA() const;
void ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); }
// 弹性恢复 /// \~chinese
void SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); } /// @brief 获取物体B的夹具
float GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); } Fixture GetFixtureB() const;
void ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); }
// 切线速度 /// \~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); void SetTangentSpeed(float speed);
/// \~chinese
/// @brief 获取切线速度
float GetTangentSpeed() const; float GetTangentSpeed() const;
b2Contact* GetB2Contact() { return contact_; } b2Contact* GetB2Contact() const;
const b2Contact* GetB2Contact() const { return contact_; } void SetB2Contact(b2Contact* contact);
void SetB2Contact(b2Contact* contact) { contact_ = contact; }
protected: bool operator== (const Contact& rhs) const;
bool operator!= (const Contact& rhs) const;
private:
b2Contact* contact_; b2Contact* contact_;
}; };
// 接触边 /// \~chinese
class KGE_API ContactEdge /// @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: public:
ContactEdge(); using value_type = Contact;
ContactEdge(b2ContactEdge* edge); using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
// 获取接触物体 inline ContactList()
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(const value_type& first)
Contact GetContact() { KGE_ASSERT(edge_); return Contact(edge_->contact); } : first_(first)
const Contact GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); } {
}
// 获取上一接触边 inline const value_type& front() const
ContactEdge GetPrev() { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); } {
const ContactEdge GetPrev() const { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); } return first_;
}
// 获取下一接触边 inline value_type& front()
ContactEdge GetNext() { KGE_ASSERT(edge_); return ContactEdge(edge_->next); } {
const ContactEdge GetNext() const { KGE_ASSERT(edge_); return ContactEdge(edge_->next); } return first_;
}
b2ContactEdge* GetB2ContactEdge() { return edge_; } inline iterator begin()
const b2ContactEdge* GetB2ContactEdge() const { return edge_; } {
void SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; } return iterator(first_);
}
protected: inline const_iterator begin() const
b2ContactEdge* edge_; {
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 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/core/Logger.h> #include <kiwano-physics/ContactEdge.h>
#include <3rd-party/StackWalker/StackWalker.h>
namespace kiwano namespace kiwano
{ {
// Display stack trace on exception namespace physics
inline void ThrowIfFailed(HRESULT hr)
{ {
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 kiwano
{ {
namespace event
{
EventType event::ContactBegin = EventType(L"ContactBegin");
EventType event::ContactEnd = EventType(L"ContactEnd");
}
namespace physics namespace physics
{ {
ContactBeginEvent::ContactBeginEvent() ContactBeginEvent::ContactBeginEvent()
: Event(event::ContactBegin) : Event(KGE_EVENT(ContactBeginEvent))
, body_a(nullptr)
, body_b(nullptr)
{ {
} }
@ -42,14 +33,10 @@ namespace kiwano
: ContactBeginEvent() : ContactBeginEvent()
{ {
this->contact = contact; this->contact = contact;
body_a = this->contact.GetFixtureA().GetBody();
body_b = this->contact.GetFixtureB().GetBody();
} }
ContactEndEvent::ContactEndEvent() ContactEndEvent::ContactEndEvent()
: Event(event::ContactEnd) : Event(KGE_EVENT(ContactEndEvent))
, body_a(nullptr)
, body_b(nullptr)
{ {
} }
@ -57,8 +44,6 @@ namespace kiwano
: ContactEndEvent() : ContactEndEvent()
{ {
this->contact = contact; 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 namespace physics
{ {
// 接触开始事件 /**
* \addtogroup Events
* @{
*/
/// \~chinese
/// @brief 物理接触开始事件
class KGE_API ContactBeginEvent class KGE_API ContactBeginEvent
: public Event : public Event
{ {
public: public:
Contact contact; Contact contact; ///< 产生的接触
Body* body_a;
Body* body_b;
ContactBeginEvent(); ContactBeginEvent();
ContactBeginEvent(Contact const& contact); ContactBeginEvent(Contact const& contact);
}; };
// 接触结束事件 /// \~chinese
/// @brief 物理接触结束事件
class KGE_API ContactEndEvent class KGE_API ContactEndEvent
: public Event : public Event
{ {
public: public:
Contact contact; Contact contact; ///< 产生的接触
Body* body_a;
Body* body_b;
ContactEndEvent(); ContactEndEvent();
ContactEndEvent(Contact const& contact); 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_); KGE_ASSERT(fixture_);
return static_cast<Body*>(fixture_->GetBody()->GetUserData()); 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 Shape Fixture::GetShape() const
{ {
KGE_ASSERT(fixture_); KGE_ASSERT(fixture_);
return Shape(fixture_->GetShape()); 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 void Fixture::GetMassData(float* mass, Point* center, float* inertia) const
{ {
KGE_ASSERT(fixture_); KGE_ASSERT(fixture_);

View File

@ -28,16 +28,24 @@ namespace kiwano
{ {
class Body; class Body;
// 夹具 /**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物理夹具
class Fixture class Fixture
{ {
public: public:
/// \~chinese
/// @brief 夹具参数
struct Param struct Param
{ {
float density = 0.f; float density = 0.f; ///< 密度
float friction = 0.2f; float friction = 0.2f; ///< 摩擦力
float restitution = 0.f; float restitution = 0.f; ///< 弹性恢复
bool is_sensor = false; bool is_sensor = false; ///< 是否是接触传感器
Param() {} Param() {}
@ -53,46 +61,195 @@ namespace kiwano
Fixture(b2Fixture* fixture); Fixture(b2Fixture* fixture);
Fixture(Body* body, Shape* shape, const Param& param); Fixture(Body* body, Shape* shape, const Param& param);
// 物体 /// \~chinese
Body* GetBody(); /// @brief 是否有效
const Body* GetBody() const; bool IsValid() const;
// 形状 /// \~chinese
/// @brief 获取夹具所在的物体
Body* GetBody() const;
/// \~chinese
/// @brief 形状
Shape GetShape() const; Shape GetShape() const;
// 下一夹具 (同一物体上) /// \~chinese
Fixture GetNext() const; /// @brief 是否是接触传感器
bool IsSensor() const;
// 接触传感器 /// \~chinese
bool IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); } /// @brief 设置夹具是否是接触传感器
void SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); } /// @details 接触传感器只会产生物理接触,而不会影响物体运动
void SetSensor(bool sensor);
// 质量数据 /// \~chinese
/// @brief 获取夹具的质量数据
void GetMassData(float* mass, Point* center, float* inertia) const; void GetMassData(float* mass, Point* center, float* inertia) const;
// 密度 /// \~chinese
float GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); } /// @brief 获取密度
void SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); } float GetDensity() const;
// 摩擦力 /// \~chinese
float GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); } /// @brief 设置密度
void SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); } void SetDensity(float density);
// 弹性恢复 /// \~chinese
float GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); } /// @brief 获取摩擦力 [N]
void SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); } 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 TestPoint(const Point& p) const;
bool IsValid() const { return !!fixture_; } b2Fixture* GetB2Fixture() const;
void SetB2Fixture(b2Fixture* fixture);
b2Fixture* GetB2Fixture() { return fixture_; } bool operator== (const Fixture& rhs) const;
const b2Fixture* GetB2Fixture() const { return fixture_; } bool operator!= (const Fixture& rhs) const;
void SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; }
protected: private:
b2Fixture* fixture_; 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) void DistanceJoint::SetLength(float length)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetLength(world_->Stage2World(length)); raw_joint_->SetLength(GetWorld()->Stage2World(length));
} }
float DistanceJoint::GetLength() const float DistanceJoint::GetLength() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetLength()); return GetWorld()->World2Stage(raw_joint_->GetLength());
} }
// //
@ -181,14 +181,14 @@ namespace kiwano
void FrictionJoint::SetMaxTorque(float length) void FrictionJoint::SetMaxTorque(float length)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetMaxTorque(world_->Stage2World(length)); raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length));
} }
float FrictionJoint::GetMaxTorque() const float FrictionJoint::GetMaxTorque() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetMaxTorque()); 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() : Joint()
, raw_joint_(nullptr) , raw_joint_(nullptr)
{ {
@ -260,6 +260,7 @@ namespace kiwano
def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body()); def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body());
def.maxForce = param.max_force; def.maxForce = param.max_force;
def.maxTorque = world->Stage2World(param.max_torque); def.maxTorque = world->Stage2World(param.max_torque);
def.correctionFactor = param.correction_factor;
Init(world, &def); Init(world, &def);
raw_joint_ = static_cast<b2MotorJoint*>(GetB2Joint()); raw_joint_ = static_cast<b2MotorJoint*>(GetB2Joint());
@ -279,14 +280,14 @@ namespace kiwano
void MotorJoint::SetMaxTorque(float length) void MotorJoint::SetMaxTorque(float length)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetMaxTorque(world_->Stage2World(length)); raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length));
} }
float MotorJoint::GetMaxTorque() const float MotorJoint::GetMaxTorque() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetMaxTorque()); return GetWorld()->World2Stage(raw_joint_->GetMaxTorque());
} }
// //
@ -326,32 +327,32 @@ namespace kiwano
float PrismaticJoint::GetJointTranslation() const float PrismaticJoint::GetJointTranslation() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetJointTranslation()); return GetWorld()->World2Stage(raw_joint_->GetJointTranslation());
} }
float PrismaticJoint::GetJointSpeed() const float PrismaticJoint::GetJointSpeed() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetJointSpeed()); return GetWorld()->World2Stage(raw_joint_->GetJointSpeed());
} }
float PrismaticJoint::GetLowerLimit() const float PrismaticJoint::GetLowerLimit() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetLowerLimit()); return GetWorld()->World2Stage(raw_joint_->GetLowerLimit());
} }
float PrismaticJoint::GetUpperLimit() const float PrismaticJoint::GetUpperLimit() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetUpperLimit()); return GetWorld()->World2Stage(raw_joint_->GetUpperLimit());
} }
void PrismaticJoint::SetLimits(float lower, float upper) void PrismaticJoint::SetLimits(float lower, float upper)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetLimits(world_->Stage2World(lower), world_->Stage2World(upper)); raw_joint_->SetLimits(GetWorld()->Stage2World(lower), GetWorld()->Stage2World(upper));
} }
// //
@ -386,14 +387,14 @@ namespace kiwano
Point PulleyJoint::GetGroundAnchorA() const Point PulleyJoint::GetGroundAnchorA() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetGroundAnchorA()); return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorA());
} }
Point PulleyJoint::GetGroundAnchorB() const Point PulleyJoint::GetGroundAnchorB() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetGroundAnchorB()); return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorB());
} }
float PulleyJoint::GetRatio() const float PulleyJoint::GetRatio() const
@ -404,26 +405,26 @@ namespace kiwano
float PulleyJoint::GetLengthA() const float PulleyJoint::GetLengthA() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetLengthA()); return GetWorld()->World2Stage(raw_joint_->GetLengthA());
} }
float PulleyJoint::GetLengthB() const float PulleyJoint::GetLengthB() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetLengthB()); return GetWorld()->World2Stage(raw_joint_->GetLengthB());
} }
float PulleyJoint::GetCurrentLengthA() const float PulleyJoint::GetCurrentLengthA() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetCurrentLengthA()); return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthA());
} }
float PulleyJoint::GetCurrentLengthB() const float PulleyJoint::GetCurrentLengthB() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetCurrentLengthB()); return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthB());
} }
// //
@ -463,44 +464,44 @@ namespace kiwano
float RevoluteJoint::GetJointAngle() const float RevoluteJoint::GetJointAngle() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return math::Radian2Degree(raw_joint_->GetJointAngle()); return math::Radian2Degree(raw_joint_->GetJointAngle());
} }
float RevoluteJoint::GetJointSpeed() const float RevoluteJoint::GetJointSpeed() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return math::Radian2Degree(raw_joint_->GetJointSpeed()); return math::Radian2Degree(raw_joint_->GetJointSpeed());
} }
float RevoluteJoint::GetLowerLimit() const float RevoluteJoint::GetLowerLimit() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return math::Radian2Degree(raw_joint_->GetLowerLimit()); return math::Radian2Degree(raw_joint_->GetLowerLimit());
} }
float RevoluteJoint::GetUpperLimit() const float RevoluteJoint::GetUpperLimit() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return math::Radian2Degree(raw_joint_->GetUpperLimit()); return math::Radian2Degree(raw_joint_->GetUpperLimit());
} }
void RevoluteJoint::SetLimits(float lower, float upper) 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)); raw_joint_->SetLimits(math::Degree2Radian(lower), math::Degree2Radian(upper));
} }
void RevoluteJoint::SetMaxMotorTorque(float torque) void RevoluteJoint::SetMaxMotorTorque(float torque)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetMaxMotorTorque(world_->Stage2World(torque)); raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque));
} }
float RevoluteJoint::GetMaxMotorTorque() const float RevoluteJoint::GetMaxMotorTorque() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetMaxMotorTorque()); return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque());
} }
// //
@ -538,14 +539,14 @@ namespace kiwano
void RopeJoint::SetMaxLength(float length) void RopeJoint::SetMaxLength(float length)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetMaxLength(world_->Stage2World(length)); raw_joint_->SetMaxLength(GetWorld()->Stage2World(length));
} }
float RopeJoint::GetMaxLength() const float RopeJoint::GetMaxLength() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetMaxLength()); return GetWorld()->World2Stage(raw_joint_->GetMaxLength());
} }
// //
@ -579,6 +580,7 @@ namespace kiwano
raw_joint_ = static_cast<b2WeldJoint*>(GetB2Joint()); raw_joint_ = static_cast<b2WeldJoint*>(GetB2Joint());
} }
// //
// WheelJoint // WheelJoint
// //
@ -615,26 +617,26 @@ namespace kiwano
float WheelJoint::GetJointTranslation() const float WheelJoint::GetJointTranslation() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetJointTranslation()); return GetWorld()->World2Stage(raw_joint_->GetJointTranslation());
} }
float WheelJoint::GetJointLinearSpeed() const float WheelJoint::GetJointLinearSpeed() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetJointLinearSpeed()); return GetWorld()->World2Stage(raw_joint_->GetJointLinearSpeed());
} }
void WheelJoint::SetMaxMotorTorque(float torque) void WheelJoint::SetMaxMotorTorque(float torque)
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
raw_joint_->SetMaxMotorTorque(world_->Stage2World(torque)); raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque));
} }
float WheelJoint::GetMaxMotorTorque() const float WheelJoint::GetMaxMotorTorque() const
{ {
KGE_ASSERT(raw_joint_ && world_); KGE_ASSERT(raw_joint_ && GetWorld());
return world_->World2Stage(raw_joint_->GetMaxMotorTorque()); return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque());
} }
// //

View File

@ -39,34 +39,51 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(WeldJoint); KGE_DECLARE_SMART_PTR(WeldJoint);
KGE_DECLARE_SMART_PTR(WheelJoint); KGE_DECLARE_SMART_PTR(WheelJoint);
// 关节 /**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 关节
class KGE_API Joint class KGE_API Joint
: public virtual RefCounter : public virtual RefCounter
{ {
public: public:
/// \~chinese
/// @brief 关节类型
enum class Type enum class Type
{ {
Unknown = 0, Unknown = 0, ///< 未知
Revolute, Revolute, ///< 旋转关节
Prismatic, Prismatic, ///< 平移关节
Distance, Distance, ///< 固定距离关节
Pulley, Pulley, ///< 滑轮关节
Mouse, Mouse, ///< 鼠标关节
Gear, Gear, ///< 齿轮关节
Wheel, Wheel, ///< 轮关节
Weld, Weld, ///< 焊接关节
Friction, Friction, ///< 摩擦关节
Rope, Rope, ///< 绳关节
Motor Motor ///< 马达关节
}; };
/// \~chinese
/// @brief 关节基础参数
struct ParamBase struct ParamBase
{ {
Body* body_a; Body* body_a; ///< 关节连接的物体A
Body* body_b; Body* body_b; ///< 关节连接的物体B
ParamBase(Body* body_a, Body* body_b) : body_a(body_a), body_b(body_b) {} ParamBase(Body* body_a, Body* body_b)
ParamBase(BodyPtr body_a, BodyPtr body_b) : body_a(body_a.get()), body_b(body_b.get()) {} : 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(); Joint();
@ -74,36 +91,46 @@ namespace kiwano
Joint(World* world, b2JointDef* joint_def); Joint(World* world, b2JointDef* joint_def);
virtual ~Joint(); virtual ~Joint();
/// \~chinese
/// @brief 初始化关节
void Init(World* world, b2JointDef* joint_def); void Init(World* world, b2JointDef* joint_def);
/// \~chinese
/// @brief 获取关节连接的物体A
BodyPtr GetBodyA() const; BodyPtr GetBodyA() const;
/// \~chinese
/// @brief 获取关节连接的物体B
BodyPtr GetBodyB() const; BodyPtr GetBodyB() const;
b2Joint* GetB2Joint() { return joint_; } /// \~chinese
const b2Joint* GetB2Joint() const { return joint_; } /// @brief 获取物理世界
World* GetWorld() const;
b2Joint* GetB2Joint() const;
void SetB2Joint(b2Joint* joint); void SetB2Joint(b2Joint* joint);
World* GetWorld() { return world_; } private:
const World* GetWorld() const { return world_; }
protected:
b2Joint* joint_; b2Joint* joint_;
World* world_; World* world_;
Type type_; Type type_;
}; };
// 固定距离关节 /// \~chinese
/// @brief 固定距离关节
class KGE_API DistanceJoint class KGE_API DistanceJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 固定距离关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor_a; Point anchor_a; ///< 关节在物体A上的连接点
Point anchor_b; Point anchor_b; ///< 关节在物体B上的连接点
float frequency_hz; float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
float damping_ratio; float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大
Param( Param(
Body* body_a, Body* body_a,
@ -136,32 +163,46 @@ namespace kiwano
DistanceJoint(World* world, b2DistanceJointDef* def); DistanceJoint(World* world, b2DistanceJointDef* def);
DistanceJoint(World* world, Param const& param); DistanceJoint(World* world, Param const& param);
/// \~chinese
/// @brief 设置关节长度
void SetLength(float length); void SetLength(float length);
/// \~chinese
/// @brief 获取关节长度
float GetLength() const; float GetLength() const;
// 设置弹簧阻尼器频率 [赫兹] /// \~chinese
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } /// @brief 设置弹簧响应速度 [赫兹]
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } void SetFrequency(float hz);
// 设置阻尼比 /// \~chinese
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } /// @brief 获取弹簧响应速度 [赫兹]
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } float GetFrequency() const;
protected: /// \~chinese
/// @brief 设置阻尼率
void SetDampingRatio(float ratio);
/// \~chinese
/// @brief 获取阻尼率
float GetDampingRatio() const;
private:
b2DistanceJoint* raw_joint_; b2DistanceJoint* raw_joint_;
}; };
// 摩擦关节 /// \~chinese
/// @brief 摩擦关节
class KGE_API FrictionJoint class KGE_API FrictionJoint
: public Joint : public Joint
{ {
public: public:
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor; Point anchor; ///< 摩擦作用点
float max_force; float max_force; ///< 最大摩擦力
float max_torque; float max_torque; ///< 最大扭力
Param( Param(
Body* body_a, Body* body_a,
@ -191,29 +232,40 @@ namespace kiwano
FrictionJoint(World* world, b2FrictionJointDef* def); FrictionJoint(World* world, b2FrictionJointDef* def);
FrictionJoint(World* world, Param const& param); FrictionJoint(World* world, Param const& param);
// 设定最大摩擦力 /// \~chinese
/// @brief 设置最大摩擦力
void SetMaxForce(float force); void SetMaxForce(float force);
/// \~chinese
/// @brief 获取最大摩擦力
float GetMaxForce() const; float GetMaxForce() const;
// 设定最大转矩 /// \~chinese
/// @brief 设置最大转矩
void SetMaxTorque(float torque); void SetMaxTorque(float torque);
/// \~chinese
/// @brief 获取最大转矩
float GetMaxTorque() const; float GetMaxTorque() const;
protected: private:
b2FrictionJoint* raw_joint_; b2FrictionJoint* raw_joint_;
}; };
// 齿轮关节 /// \~chinese
/// @brief 齿轮关节
class KGE_API GearJoint class KGE_API GearJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 齿轮关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
JointPtr joint_a; JointPtr joint_a; ///< 关节A旋转关节/平移关节)
JointPtr joint_b; JointPtr joint_b; ///< 关节B旋转关节/平移关节)
float ratio; float ratio; ///< 齿轮传动比
Param( Param(
Joint* joint_a, Joint* joint_a,
@ -237,27 +289,34 @@ namespace kiwano
GearJoint(); GearJoint();
GearJoint(World* world, b2GearJointDef* def); GearJoint(World* world, b2GearJointDef* def);
GearJoint(World* world, Param const& param); GearJoint(World* world, Param param);
// 设定齿轮传动比 /// \~chinese
/// @brief 设定齿轮传动比
void SetRatio(float ratio); void SetRatio(float ratio);
/// \~chinese
/// @brief 获取齿轮传动比
float GetRatio() const; float GetRatio() const;
protected: private:
b2GearJoint* raw_joint_; b2GearJoint* raw_joint_;
}; };
// 马达关节 /// \~chinese
/// @brief 马达关节
class KGE_API MotorJoint class KGE_API MotorJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 马达关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
float max_force; float max_force; ///< 最大摩擦力
float max_torque; float max_torque; ///< 最大转矩
float correction_factor; float correction_factor; ///< 位置矫正因子(范围 0-1
Param( Param(
Body* body_a, Body* body_a,
@ -287,34 +346,45 @@ namespace kiwano
MotorJoint(World* world, b2MotorJointDef* def); MotorJoint(World* world, b2MotorJointDef* def);
MotorJoint(World* world, Param const& param); MotorJoint(World* world, Param const& param);
// 设定最大摩擦力 /// \~chinese
/// @brief 设置最大摩擦力
void SetMaxForce(float force); void SetMaxForce(float force);
/// \~chinese
/// @brief 获取最大摩擦力
float GetMaxForce() const; float GetMaxForce() const;
// 设定最大转矩 /// \~chinese
/// @brief 设置最大转矩
void SetMaxTorque(float torque); void SetMaxTorque(float torque);
/// \~chinese
/// @brief 获取最大转矩
float GetMaxTorque() const; float GetMaxTorque() const;
protected: private:
b2MotorJoint* raw_joint_; b2MotorJoint* raw_joint_;
}; };
// 平移关节 /// \~chinese
/// @brief 平移关节
class KGE_API PrismaticJoint class KGE_API PrismaticJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 平移关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor; Point anchor; ///< 关节位置
Vec2 axis; Vec2 axis; ///< 物体A滑动的方向
bool enable_limit; bool enable_limit; ///< 是否启用限制
float lower_translation; float lower_translation; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果
float upper_translation; float upper_translation; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果
bool enable_motor; bool enable_motor; ///< 是否启用马达
float max_motor_force; float max_motor_force; ///< 最大马达力 [N]
float motor_speed; float motor_speed; ///< 马达转速 [degree/s]
Param( Param(
Body* body_a, Body* body_a,
@ -359,45 +429,82 @@ namespace kiwano
PrismaticJoint(World* world, b2PrismaticJointDef* def); PrismaticJoint(World* world, b2PrismaticJointDef* def);
PrismaticJoint(World* world, Param const& param); 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; float GetJointTranslation() const;
/// \~chinese
/// @brief 获取关节速度
float GetJointSpeed() const; float GetJointSpeed() const;
bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } /// \~chinese
void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } /// @brief 是否启用关节限制
bool IsLimitEnabled() const;
/// \~chinese
/// @brief 设置是否启用关节限制
void EnableLimit(bool flag);
/// \~chinese
/// @brief 获取平移最小限制
float GetLowerLimit() const; float GetLowerLimit() const;
/// \~chinese
/// @brief 获取平移最大限制
float GetUpperLimit() const; float GetUpperLimit() const;
/// \~chinese
/// @brief 设置关节限制
void SetLimits(float lower, float upper); void SetLimits(float lower, float upper);
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } /// \~chinese
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } /// @brief 是否启用马达
bool IsMotorEnabled() const;
// 设置马达转速 [degree/s] /// \~chinese
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } /// @brief 设置是否启用马达
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } void EnableMotor(bool flag);
// 设定最大马达力 [N] /// \~chinese
void SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); } /// @brief 设置马达转速 [degree/s]
float GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); } 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_; b2PrismaticJoint* raw_joint_;
}; };
// 滑轮关节 /// \~chinese
/// @brief 滑轮关节
class KGE_API PulleyJoint class KGE_API PulleyJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 滑轮关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor_a; Point anchor_a; ///< 关节在物体A上的作用点
Point anchor_b; Point anchor_b; ///< 关节在物体B上的作用点
Point ground_anchor_a; Point ground_anchor_a; ///< 物体A对应的滑轮的位置
Point ground_anchor_b; Point ground_anchor_b; ///< 物体B对应的滑轮的位置
float ratio; float ratio; ///< 滑轮比,关节传动时,滑轮上升和下降的两头的位移比例
Param( Param(
Body* body_a, Body* body_a,
@ -433,36 +540,56 @@ namespace kiwano
PulleyJoint(World* world, b2PulleyJointDef* def); PulleyJoint(World* world, b2PulleyJointDef* def);
PulleyJoint(World* world, Param const& param); PulleyJoint(World* world, Param const& param);
/// \~chinese
/// @brief 物体A对应的滑轮的位置
Point GetGroundAnchorA() const; Point GetGroundAnchorA() const;
/// \~chinese
/// @brief 物体B对应的滑轮的位置
Point GetGroundAnchorB() const; Point GetGroundAnchorB() const;
/// \~chinese
/// @brief 获取滑轮传动比
float GetRatio() const; float GetRatio() const;
/// \~chinese
/// @brief 获取物体A与滑轮的距离
float GetLengthA() const; float GetLengthA() const;
/// \~chinese
/// @brief 获取物体B与滑轮的距离
float GetLengthB() const; float GetLengthB() const;
/// \~chinese
/// @brief 获取物体A与滑轮的当前距离
float GetCurrentLengthA() const; float GetCurrentLengthA() const;
/// \~chinese
/// @brief 获取物体B与滑轮的当前距离
float GetCurrentLengthB() const; float GetCurrentLengthB() const;
protected: private:
b2PulleyJoint* raw_joint_; b2PulleyJoint* raw_joint_;
}; };
// 旋转关节 /// \~chinese
/// @brief 旋转关节
class KGE_API RevoluteJoint class KGE_API RevoluteJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 旋转关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor; Point anchor; ///< 关节位置
bool enable_limit; bool enable_limit; ///< 是否启用限制
float lower_angle; float lower_angle; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果
float upper_angle; float upper_angle; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果
bool enable_motor; bool enable_motor; ///< 是否启用马达
float max_motor_torque; float max_motor_torque; ///< 最大马达力 [N]
float motor_speed; float motor_speed; ///< 马达转速 [degree/s]
Param( Param(
Body* body_a, Body* body_a,
@ -504,43 +631,80 @@ namespace kiwano
RevoluteJoint(World* world, b2RevoluteJointDef* def); RevoluteJoint(World* world, b2RevoluteJointDef* def);
RevoluteJoint(World* world, Param const& param); 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; float GetJointAngle() const;
/// \~chinese
/// @brief 获取关节速度
float GetJointSpeed() const; float GetJointSpeed() const;
bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } /// \~chinese
void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } /// @brief 是否启用关节限制
bool IsLimitEnabled() const;
/// \~chinese
/// @brief 设置是否启用关节限制
void EnableLimit(bool flag);
/// \~chinese
/// @brief 获取平移最小限制
float GetLowerLimit() const; float GetLowerLimit() const;
/// \~chinese
/// @brief 获取平移最大限制
float GetUpperLimit() const; float GetUpperLimit() const;
/// \~chinese
/// @brief 设置关节限制
void SetLimits(float lower, float upper); void SetLimits(float lower, float upper);
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } /// \~chinese
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } /// @brief 是否启用马达
bool IsMotorEnabled() const;
// 设置马达转速 [degree/s] /// \~chinese
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } /// @brief 设置是否启用马达
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } 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); void SetMaxMotorTorque(float torque);
/// \~chinese
/// @brief 获取最大马达转矩 [N/m]
float GetMaxMotorTorque() const; float GetMaxMotorTorque() const;
protected: private:
b2RevoluteJoint* raw_joint_; b2RevoluteJoint* raw_joint_;
}; };
// 绳关节 /// \~chinese
/// @brief 绳关节
class KGE_API RopeJoint class KGE_API RopeJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 绳关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point local_anchor_a; Point local_anchor_a; ///< 关节在物体A上的连接点
Point local_anchor_b; Point local_anchor_b; ///< 关节在物体B上的连接点
float max_length; float max_length; ///< 绳索最大长度
Param( Param(
Body* body_a, Body* body_a,
@ -570,24 +734,32 @@ namespace kiwano
RopeJoint(World* world, b2RopeJointDef* def); RopeJoint(World* world, b2RopeJointDef* def);
RopeJoint(World* world, Param const& param); RopeJoint(World* world, Param const& param);
/// \~chinese
/// @brief 设置关节最大长度
void SetMaxLength(float length); void SetMaxLength(float length);
/// \~chinese
/// @brief 获取关节最大长度
float GetMaxLength() const; float GetMaxLength() const;
protected: private:
b2RopeJoint* raw_joint_; b2RopeJoint* raw_joint_;
}; };
// 焊接关节 /// \~chinese
/// @brief 焊接关节
class KGE_API WeldJoint class KGE_API WeldJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 焊接关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor; Point anchor; ///< 焊接位置
float frequency_hz; float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
float damping_ratio; float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大
Param( Param(
Body* body_a, Body* body_a,
@ -617,33 +789,48 @@ namespace kiwano
WeldJoint(World* world, b2WeldJointDef* def); WeldJoint(World* world, b2WeldJointDef* def);
WeldJoint(World* world, Param const& param); WeldJoint(World* world, Param const& param);
// 设置弹簧阻尼器频率 [赫兹] /// \~chinese
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } /// @brief 获取物体B相对于物体A的角度
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } float GetReferenceAngle() const;
// 设置阻尼比 /// \~chinese
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } /// @brief 设置弹簧响应速度 [赫兹]
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } 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_; b2WeldJoint* raw_joint_;
}; };
// 轮关节 /// \~chinese
/// @brief 轮关节
class KGE_API WheelJoint class KGE_API WheelJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 轮关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point anchor; Point anchor; ///< 轮关节位置
Vec2 axis; Vec2 axis; ///< 物体A滑动方向
bool enable_motor; bool enable_motor; ///< 是否启用马达
float max_motor_torque; float max_motor_torque; ///< 最大马达力 [N]
float motor_speed; float motor_speed; ///< 马达转速 [degree/s]
float frequency_hz; float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
float damping_ratio; float damping_ratio; ///< 弹簧阻尼率,值越大关节运动阻尼越大
Param( Param(
Body* body_a, Body* body_a,
@ -685,45 +872,82 @@ namespace kiwano
WheelJoint(World* world, b2WheelJointDef* def); WheelJoint(World* world, b2WheelJointDef* def);
WheelJoint(World* world, Param const& param); WheelJoint(World* world, Param const& param);
/// \~chinese
/// @brief 获取关节当前的平移距离
float GetJointTranslation() const; float GetJointTranslation() const;
/// \~chinese
/// @brief 获取关节当前的线性速度
float GetJointLinearSpeed() const; 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(); } /// \~chinese
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } /// @brief 获取关节当前的角度
float GetJointAngle() const;
// 设置马达转速 [degree/s] /// \~chinese
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } /// @brief 获取关节当前的旋转速度
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } 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); void SetMaxMotorTorque(float torque);
/// \~chinese
/// @brief 获取最大马达转矩 [N/m]
float GetMaxMotorTorque() const; float GetMaxMotorTorque() const;
void SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); } /// \~chinese
float GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); } /// @brief 设置弹簧响应速度
void SetSpringFrequencyHz(float hz);
void SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); } /// \~chinese
float GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); } /// @brief 获取弹簧响应速度
float GetSpringFrequencyHz() const;
protected: /// \~chinese
/// @brief 设置弹簧阻尼率
void SetSpringDampingRatio(float ratio);
/// \~chinese
/// @brief 获取弹簧阻尼率
float GetSpringDampingRatio() const;
private:
b2WheelJoint* raw_joint_; b2WheelJoint* raw_joint_;
}; };
// 鼠标关节 /// \~chinese
// 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置 /// @brief 鼠标关节
/// @details 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
class KGE_API MouseJoint class KGE_API MouseJoint
: public Joint : public Joint
{ {
public: public:
/// \~chinese
/// @brief 鼠标关节参数
struct Param : public Joint::ParamBase struct Param : public Joint::ParamBase
{ {
Point target; Point target; ///< 关节作用目标位置
float max_force; float max_force; ///< 作用在物体A上的最大力
float frequency_hz; float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
float damping_ratio; float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大
Param( Param(
Body* body_a, Body* body_a,
@ -740,14 +964,7 @@ namespace kiwano
, damping_ratio(damping_ratio) , damping_ratio(damping_ratio)
{} {}
Param( Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f, float damping_ratio = 0.7f)
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) : 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, b2MouseJointDef* def);
MouseJoint(World* world, Param const& param); MouseJoint(World* world, Param const& param);
// 设定最大摩擦力 [N] /// \~chinese
/// @brief 设定最大摩擦力 [N]
void SetMaxForce(float force); void SetMaxForce(float force);
/// \~chinese
/// @brief 获取最大摩擦力 [N]
float GetMaxForce() const; float GetMaxForce() const;
// 设置响应速度 [hz] /// \~chinese
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } /// @brief 设置响应速度 [hz]
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } void SetFrequency(float hz);
// 设置阻尼比 /// \~chinese
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } /// @brief 获取响应速度 [hz]
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } float GetFrequency() const;
protected: /// \~chinese
/// @brief 设置阻尼率
void SetDampingRatio(float ratio);
/// \~chinese
/// @brief 获取阻尼率
float GetDampingRatio() const;
private:
b2MouseJoint* raw_joint_; 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() b2Shape* Shape::GetB2Shape() const
{
return shape_;
}
const b2Shape* Shape::GetB2Shape() const
{ {
return shape_; return shape_;
} }

View File

@ -26,25 +26,35 @@ namespace kiwano
namespace physics namespace physics
{ {
class World; class World;
class Fixture;
// 形状基类 /**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 形状基类
class KGE_API Shape class KGE_API Shape
{ {
friend class Fixture;
public: public:
Shape(); Shape();
Shape(b2Shape* shape); Shape(b2Shape* shape);
b2Shape* GetB2Shape(); b2Shape* GetB2Shape() const;
const b2Shape* GetB2Shape() const;
void SetB2Shape(b2Shape* shape); void SetB2Shape(b2Shape* shape);
private:
virtual void FitWorld(World* world) {} virtual void FitWorld(World* world) {}
protected: private:
b2Shape* shape_; b2Shape* shape_;
}; };
// 圆形形状 /// \~chinese
/// @brief 圆形形状
class KGE_API CircleShape class KGE_API CircleShape
: public Shape : public Shape
{ {
@ -55,15 +65,17 @@ namespace kiwano
void Set(float radius, Point const& offset = Point()); void Set(float radius, Point const& offset = Point());
private:
void FitWorld(World* world) override; void FitWorld(World* world) override;
protected: private:
float radius_; float radius_;
Point offset_; Point offset_;
b2CircleShape circle_; b2CircleShape circle_;
}; };
// 盒子形状 /// \~chinese
/// @brief 盒子形状
class KGE_API BoxShape class KGE_API BoxShape
: public Shape : public Shape
{ {
@ -74,16 +86,18 @@ namespace kiwano
void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f); void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
private:
void FitWorld(World* world) override; void FitWorld(World* world) override;
protected: private:
float rotation_; float rotation_;
Vec2 box_size_; Vec2 box_size_;
Point offset_; Point offset_;
b2PolygonShape polygon_; b2PolygonShape polygon_;
}; };
// 多边形形状 /// \~chinese
/// @brief 多边形形状
class KGE_API PolygonShape class KGE_API PolygonShape
: public Shape : public Shape
{ {
@ -94,14 +108,16 @@ namespace kiwano
void Set(Vector<Point> const& vertexs); void Set(Vector<Point> const& vertexs);
private:
void FitWorld(World* world) override; void FitWorld(World* world) override;
protected: private:
Vector<Point> vertexs_; Vector<Point> vertexs_;
b2PolygonShape polygon_; b2PolygonShape polygon_;
}; };
// 线段形状, 用于表示一条边 /// \~chinese
/// @brief 线段形状, 用于表示一条边
class KGE_API EdgeShape class KGE_API EdgeShape
: public Shape : public Shape
{ {
@ -112,14 +128,16 @@ namespace kiwano
void Set(Point const& p1, Point const& p2); void Set(Point const& p1, Point const& p2);
private:
void FitWorld(World* world) override; void FitWorld(World* world) override;
protected: private:
Point p_[2]; Point p_[2];
b2EdgeShape edge_; b2EdgeShape edge_;
}; };
// 链式形状 /// \~chinese
/// @brief 链式形状
class KGE_API ChainShape class KGE_API ChainShape
: public Shape : public Shape
{ {
@ -130,12 +148,15 @@ namespace kiwano
void Set(Vector<Point> const& vertexs, bool loop = false); void Set(Vector<Point> const& vertexs, bool loop = false);
private:
void FitWorld(World* world) override; void FitWorld(World* world) override;
protected: private:
bool loop_; bool loop_;
Vector<Point> vertexs_; Vector<Point> vertexs_;
b2ChainShape chain_; b2ChainShape chain_;
}; };
/** @} */
} }
} }

View File

@ -27,7 +27,7 @@ namespace kiwano
{ {
namespace 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 class World::DestructionListener : public b2DestructionListener
@ -85,7 +85,7 @@ namespace kiwano
: world_(b2Vec2(0, 10.0f)) : world_(b2Vec2(0, 10.0f))
, vel_iter_(6) , vel_iter_(6)
, pos_iter_(2) , pos_iter_(2)
, global_scale_(DefaultGlobalScale) , global_scale_(default_global_scale)
, destruction_listener_(nullptr) , destruction_listener_(nullptr)
, contact_listener_(nullptr) , contact_listener_(nullptr)
, removing_joint_(false) , removing_joint_(false)
@ -225,36 +225,25 @@ namespace kiwano
world_.SetGravity(b2Vec2(gravity.x, gravity.y)); world_.SetGravity(b2Vec2(gravity.x, gravity.y));
} }
ContactList World::GetContactList()
{
return ContactList(Contact(world_.GetContactList()));
}
void World::Update(Duration dt) 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_); world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
b2Body* b2body = world_.GetBodyList();
while (b2body)
{ {
b2Body* b2body = world_.GetBodyList(); Body* body = static_cast<Body*>(b2body->GetUserData());
while (b2body) if (body && body->GetType() != Body::Type::Static)
{ {
Body* body = static_cast<Body*>(b2body->GetUserData()); body->UpdateActor();
if (body && body->GetType() != Body::Type::Static)
{
body->UpdateActor();
}
b2body = b2body->GetNext();
} }
b2body = b2body->GetNext();
} }
Stage::Update(dt); Stage::Update(dt);

View File

@ -26,7 +26,22 @@ namespace kiwano
{ {
namespace physics namespace physics
{ {
// 物理世界 KGE_DECLARE_SMART_PTR(World);
/**
* \~chinese
* \defgroup Physics
*/
/**
* \addtogroup Physics
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API World class KGE_API World
: public Stage : public Stage
{ {
@ -38,54 +53,86 @@ namespace kiwano
virtual ~World(); virtual ~World();
// 获取重力 /// \~chinese
/// @brief 获取重力 [N]
Vec2 GetGravity() const; Vec2 GetGravity() const;
// 设置重力 /// \~chinese
/// @brief 设置重力 [N]
void SetGravity(Vec2 gravity); void SetGravity(Vec2 gravity);
// 获取全局缩放比例 /// \~chinese
inline float GetGlobalScale() const { return global_scale_; } /// @brief 获取物理接触列表
ContactList GetContactList();
// 设置全局缩放比例 /// \~chinese
inline void SetGlobalScale(float scale) { global_scale_ = scale; } /// @brief 获取全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
float GetGlobalScale() const;
// 游戏世界单位转换为物理世界单位 /// \~chinese
inline float World2Stage(float value) const { return value * GetGlobalScale(); } /// @brief 设置全局缩放比例
inline Point World2Stage(const b2Vec2& pos) const { return Point(World2Stage(pos.x), World2Stage(pos.y)); } /// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
void SetGlobalScale(float scale);
// 物理世界单位转换为游戏世界单位 /// \~chinese
inline float Stage2World(float value) const { return value / GetGlobalScale(); } /// @brief 游戏世界单位转换为物理世界单位
inline b2Vec2 Stage2World(const Point& pos) const { return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); } /// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
float World2Stage(float value) const;
// 设置速度迭代次数, 默认为 6 /// \~chinese
inline void SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; } /// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
Vec2 World2Stage(const b2Vec2& pos) const;
// 设置位置迭代次数, 默认为 2 /// \~chinese
inline void SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; } /// @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(); b2World* GetB2World();
const b2World* GetB2World() const; const b2World* GetB2World() const;
private: private:
// 移除物体 /// \~chinese
/// @brief 移除物体
void RemoveBody(Body* body); void RemoveBody(Body* body);
// 移除所有物体 /// \~chinese
/// @brief 移除所有物体
void RemoveAllBodies(); void RemoveAllBodies();
// 添加关节 /// \~chinese
/// @brief 添加关节
void AddJoint(Joint* joint); void AddJoint(Joint* joint);
// 移除关节 /// \~chinese
/// @brief 移除关节
void RemoveJoint(Joint* joint); void RemoveJoint(Joint* joint);
// 移除所有关节 /// \~chinese
/// @brief 移除所有关节
void RemoveAllJoints(); void RemoveAllJoints();
// 关节被移除 /// \~chinese
/// @brief 关节被移除
void JointRemoved(b2Joint* joint); void JointRemoved(b2Joint* joint);
protected:
void Update(Duration dt) override; void Update(Duration dt) override;
private: private:
@ -106,6 +153,47 @@ namespace kiwano
Vector<Joint*> joints_; 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 namespace physics
{ {
inline b2Vec2 Stage2World(const Point& pos) { return b2Vec2(pos.x, pos.y); } inline b2Vec2 Stage2World(const Vec2& pos) { return b2Vec2(pos.x, pos.y); }
inline Point World2Stage(const b2Vec2& pos) { return Point(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()) if (children_.empty())
{ {
OnRender(rt); if (CheckVisibilty(rt))
{
PrepareToRender(rt);
OnRender(rt);
}
} }
else else
{ {
@ -108,7 +112,11 @@ namespace kiwano
child = child->next_item().get(); child = child->next_item().get();
} }
OnRender(rt); if (CheckVisibilty(rt))
{
PrepareToRender(rt);
OnRender(rt);
}
while (child) while (child)
{ {
@ -118,10 +126,10 @@ namespace kiwano
} }
} }
void Actor::PrepareRender(RenderTarget* rt) void Actor::PrepareToRender(RenderTarget* rt)
{ {
rt->SetTransform(transform_matrix_); rt->SetTransform(transform_matrix_);
rt->SetOpacity(displayed_opacity_); rt->SetBrushOpacity(GetDisplayedOpacity());
} }
void Actor::RenderBorder(RenderTarget* rt) void Actor::RenderBorder(RenderTarget* rt)
@ -132,10 +140,10 @@ namespace kiwano
rt->SetTransform(transform_matrix_); rt->SetTransform(transform_matrix_);
rt->SetDefaultBrushColor(Color(Color::Red, .4f)); rt->SetCurrentBrush(GetStage()->GetBorderFillBrush());
rt->FillRectangle(bounds); rt->FillRectangle(bounds);
rt->SetDefaultBrushColor(Color(Color::Red, .8f)); rt->SetCurrentBrush(GetStage()->GetBorderStrokeBrush());
rt->DrawRectangle(bounds, 2.f); rt->DrawRectangle(bounds, 2.f);
} }
@ -150,7 +158,15 @@ namespace kiwano
if (dirty_visibility_) if (dirty_visibility_)
{ {
dirty_visibility_ = false; 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_; return visible_in_rt_;
} }
@ -169,21 +185,21 @@ namespace kiwano
if (responsible_) if (responsible_)
{ {
if (evt.type == event::MouseMove) if (evt.IsType<MouseMoveEvent>())
{ {
auto mouse_evt = evt.SafeCast<MouseMoveEvent>(); auto& mouse_evt = evt.SafeCast<MouseMoveEvent>();
if (!mouse_evt->target && ContainsPoint(mouse_evt->pos)) if (!mouse_evt.target && ContainsPoint(mouse_evt.pos))
{ {
mouse_evt->target = this; mouse_evt.target = this;
if (!hover_) if (!hover_)
{ {
hover_ = true; hover_ = true;
MouseHoverEvent hover; MouseHoverEvent hover;
hover.pos = mouse_evt->pos; hover.pos = mouse_evt.pos;
hover.left_btn_down = mouse_evt->left_btn_down; hover.left_btn_down = mouse_evt.left_btn_down;
hover.right_btn_down = mouse_evt->right_btn_down; hover.right_btn_down = mouse_evt.right_btn_down;
hover.target = this; hover.target = this;
EventDispatcher::Dispatch(hover); EventDispatcher::Dispatch(hover);
} }
@ -194,33 +210,33 @@ namespace kiwano
pressed_ = false; pressed_ = false;
MouseOutEvent out; MouseOutEvent out;
out.pos = mouse_evt->pos; out.pos = mouse_evt.pos;
out.left_btn_down = mouse_evt->left_btn_down; out.left_btn_down = mouse_evt.left_btn_down;
out.right_btn_down = mouse_evt->right_btn_down; out.right_btn_down = mouse_evt.right_btn_down;
out.target = this; out.target = this;
EventDispatcher::Dispatch(out); EventDispatcher::Dispatch(out);
} }
} }
if (evt.type == event::MouseDown && hover_) if (evt.IsType<MouseDownEvent>() && hover_)
{ {
pressed_ = true; 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; pressed_ = false;
auto mouse_up_evt = evt.SafeCast<MouseUpEvent>(); auto mouse_up_evt = evt.SafeCast<MouseUpEvent>();
mouse_up_evt->target = this; mouse_up_evt.target = this;
MouseClickEvent click; MouseClickEvent click;
click.pos = mouse_up_evt->pos; click.pos = mouse_up_evt.pos;
click.left_btn_down = mouse_up_evt->left_btn_down; click.left_btn_down = mouse_up_evt.left_btn_down;
click.right_btn_down = mouse_up_evt->right_btn_down; click.right_btn_down = mouse_up_evt.right_btn_down;
click.target = this; click.target = this;
click.button = mouse_up_evt->button; click.button = mouse_up_evt.button;
EventDispatcher::Dispatch(click); EventDispatcher::Dispatch(click);
} }
} }
@ -272,7 +288,7 @@ namespace kiwano
} }
// update children's transform // 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; child->dirty_transform_ = true;
} }
@ -481,7 +497,7 @@ namespace kiwano
{ {
if (parent == child) 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; return;
} }
} }
@ -527,11 +543,11 @@ namespace kiwano
Vector<ActorPtr> children; Vector<ActorPtr> children;
size_t hash_code = std::hash<String>{}(name); 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)) if (child->hash_name_ == hash_code && child->IsName(name))
{ {
children.push_back(child); children.push_back(const_cast<Actor*>(child));
} }
} }
return children; return children;
@ -541,11 +557,11 @@ namespace kiwano
{ {
size_t hash_code = std::hash<String>{}(name); 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)) if (child->hash_name_ == hash_code && child->IsName(name))
{ {
return child; return const_cast<Actor*>(child);
} }
} }
return nullptr; return nullptr;

View File

@ -19,7 +19,10 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #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/Transform.h>
#include <kiwano/2d/action/ActionManager.h> #include <kiwano/2d/action/ActionManager.h>
#include <kiwano/core/TimerManager.h> #include <kiwano/core/TimerManager.h>
@ -27,10 +30,27 @@
namespace kiwano namespace kiwano
{ {
class Stage;
class Director; class Director;
class RenderTarget; class RenderTarget;
// 角色 KGE_DECLARE_SMART_PTR(Actor);
/**
* \~chinese
* \defgroup Actors
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
* @details
*/
class KGE_API Actor class KGE_API Actor
: public ObjectBase : public ObjectBase
, public TimerManager , public TimerManager
@ -43,353 +63,376 @@ namespace kiwano
friend IntrusiveList<ActorPtr>; friend IntrusiveList<ActorPtr>;
public: public:
using Children = IntrusiveList<ActorPtr>; /// \~chinese
using UpdateCallback = Function<void(Duration)>; /// @brief 子成员列表
using Children = IntrusiveList<ActorPtr>;
/// \~chinese
/// @brief 角色更新回调函数
using UpdateCallback = Function<void(Duration)>;
Actor(); Actor();
// 更新角色 /// \~chinese
/// @brief 更新角色
/// @details 每帧画面刷新前调用该函数,重载该函数以实现角色的更新处理
/// @param dt 距上一次更新的时间间隔
virtual void OnUpdate(Duration dt); virtual void OnUpdate(Duration dt);
// 渲染角色 /// \~chinese
/// @brief 渲染角色
/// @details 每帧画面刷新时调用该函数,默认不进行渲染,重载该函数以实现具体渲染过程
/// @param rt 渲染目标
virtual void OnRender(RenderTarget* rt); virtual void OnRender(RenderTarget* rt);
// 获取显示状态 /// \~chinese
/// @brief 获取显示状态
bool IsVisible() const; bool IsVisible() const;
// 获取响应状态 /// \~chinese
/// @brief 获取响应状态
bool IsResponsible() const; bool IsResponsible() const;
// 是否启用级联透明度 /// \~chinese
/// @brief 是否启用级联透明度
bool IsCascadeOpacityEnabled() const; bool IsCascadeOpacityEnabled() const;
// 获取名称的 Hash 值 /// \~chinese
/// @brief 获取名称的 Hash 值
size_t GetHashName() const; size_t GetHashName() const;
// 获取 Z 轴顺序 /// \~chinese
/// @brief 获取 Z 轴顺序
int GetZOrder() const; int GetZOrder() const;
// 获取坐标 /// \~chinese
/// @brief 获取坐标
Point const& GetPosition() const; Point const& GetPosition() const;
// 获取 x 坐标 /// \~chinese
/// @brief 获取 x 坐标
float GetPositionX() const; float GetPositionX() const;
// 获取 y 坐标 /// \~chinese
/// @brief 获取 y 坐标
float GetPositionY() const; float GetPositionY() const;
// 获取缩放比例 /// \~chinese
/// @brief 获取缩放比例
Point const& GetScale() const; Point const& GetScale() const;
// 获取横向缩放比例 /// \~chinese
/// @brief 获取横向缩放比例
float GetScaleX() const; float GetScaleX() const;
// 获取纵向缩放比例 /// \~chinese
/// @brief 获取纵向缩放比例
float GetScaleY() const; float GetScaleY() const;
// 获取错切角度 /// \~chinese
/// @brief 获取错切角度
Point const& GetSkew() const; Point const& GetSkew() const;
// 获取横向错切角度 /// \~chinese
/// @brief 获取横向错切角度
float GetSkewX() const; float GetSkewX() const;
// 获取纵向错切角度 /// \~chinese
/// @brief 获取纵向错切角度
float GetSkewY() const; float GetSkewY() const;
// 获取旋转角度 /// \~chinese
/// @brief 获取旋转角度
float GetRotation() const; float GetRotation() const;
// 获取宽度 /// \~chinese
/// @brief 获取宽度
float GetWidth() const; float GetWidth() const;
// 获取高度 /// \~chinese
/// @brief 获取高度
float GetHeight() const; float GetHeight() const;
// 获取大小 /// \~chinese
/// @brief 获取大小
Size const& GetSize() const; Size const& GetSize() const;
// 获取缩放后的宽度 /// \~chinese
/// @brief 获取缩放后的宽度
float GetScaledWidth() const; float GetScaledWidth() const;
// 获取缩放后的高度 /// \~chinese
/// @brief 获取缩放后的高度
float GetScaledHeight() const; float GetScaledHeight() const;
// 获取缩放后的大小 /// \~chinese
/// @brief 获取缩放后的大小
Size GetScaledSize() const; Size GetScaledSize() const;
// 获取锚点 /// \~chinese
/// @brief 获取锚点
Point const& GetAnchor() const; Point const& GetAnchor() const;
// 获取 x 方向锚点 /// \~chinese
/// @brief 获取 x 方向锚点
float GetAnchorX() const; float GetAnchorX() const;
// 获取 y 方向锚点 /// \~chinese
/// @brief 获取 y 方向锚点
float GetAnchorY() const; float GetAnchorY() const;
// 获取透明度 /// \~chinese
/// @brief 获取透明度
float GetOpacity() const; float GetOpacity() const;
// 获取显示透明度 /// \~chinese
/// @brief 获取显示透明度
float GetDisplayedOpacity() const; float GetDisplayedOpacity() const;
// 获取变换 /// \~chinese
/// @brief 获取变换
Transform GetTransform() const; Transform GetTransform() const;
// 获取父角色 /// \~chinese
/// @brief 获取父角色
Actor* GetParent() const; Actor* GetParent() const;
// 获取所在舞台 /// \~chinese
/// @brief 获取所在舞台
Stage* GetStage() const; Stage* GetStage() const;
// 获取边框 /// \~chinese
/// @brief 获取边框
virtual Rect GetBounds() const; virtual Rect GetBounds() const;
// 获取外切包围盒 /// \~chinese
/// @brief 获取外切包围盒
virtual Rect GetBoundingBox() const; virtual Rect GetBoundingBox() const;
// 获取二维变换矩阵 /// \~chinese
/// @brief 获取二维变换矩阵
Matrix3x2 const& GetTransformMatrix() const; Matrix3x2 const& GetTransformMatrix() const;
// 获取二维变换的逆矩阵 /// \~chinese
/// @brief 获取二维变换的逆矩阵
Matrix3x2 const& GetTransformInverseMatrix() const; Matrix3x2 const& GetTransformInverseMatrix() const;
// 设置是否显示 /// \~chinese
void SetVisible( /// @brief 设置角色是否可见
bool val void SetVisible(bool val);
);
// 设置名称 /// \~chinese
void SetName( /// @brief 设置名称
String const& name void SetName(String const& name);
);
// 设置坐标 /// \~chinese
virtual void SetPosition( /// @brief 设置坐标
Point const& point virtual void SetPosition(Point const& point);
);
// 设置坐标 /// \~chinese
void SetPosition( /// @brief 设置坐标
float x, void SetPosition(float x, float y);
float y
);
// 设置横坐标 /// \~chinese
void SetPositionX( /// @brief 设置横坐标
float x void SetPositionX(float x);
);
// 设置纵坐标 /// \~chinese
void SetPositionY( /// @brief 设置纵坐标
float y void SetPositionY(float y);
);
// 移动坐标 /// \~chinese
void Move( /// @brief 移动坐标
Vec2 const& v void Move(Vec2 const& v);
);
// 移动坐标 /// \~chinese
void Move( /// @brief 移动坐标
float vx, void Move(float vx, float vy);
float vy
);
// 设置缩放比例 /// \~chinese
// 默认为 (1.0, 1.0) /// @brief 设置缩放比例,默认为 (1.0, 1.0)
virtual void SetScale( virtual void SetScale(Vec2 const& scale);
Vec2 const& scale
);
// 设置缩放比例 /// \~chinese
// 默认为 (1.0, 1.0) /// @brief 设置缩放比例,默认为 (1.0, 1.0)
void SetScale( void SetScale(float scalex, float scaley);
float scalex,
float scaley
);
// 设置错切角度 /// \~chinese
// 默认为 (0, 0) /// @brief 设置错切角度,默认为 (0, 0)
virtual void SetSkew( virtual void SetSkew(Vec2 const& skew);
Vec2 const& skew
);
// 设置错切角度 /// \~chinese
// 默认为 (0, 0) /// @brief 设置错切角度,默认为 (0, 0)
void SetSkew( void SetSkew(float skewx, float skewy);
float skewx,
float skewy
);
// 设置旋转角度 /// \~chinese
// 默认为 0 /// @brief 设置旋转角度,默认为 0
virtual void SetRotation( virtual void SetRotation(float rotation);
float rotation
);
// 设置锚点位置 /// \~chinese
// 默认为 (0, 0), 范围 [0, 1] /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
virtual void SetAnchor( virtual void SetAnchor(Vec2 const& anchor);
Vec2 const& anchor
);
// 设置锚点位置 /// \~chinese
// 默认为 (0, 0), 范围 [0, 1] /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
void SetAnchor( void SetAnchor(float anchorx, float anchory);
float anchorx,
float anchory
);
// 修改宽度 /// \~chinese
virtual void SetWidth( /// @brief 修改宽度
float width virtual void SetWidth(float width);
);
// 修改高度 /// \~chinese
virtual void SetHeight( /// @brief 修改高度
float height virtual void SetHeight(float height);
);
// 修改大小 /// \~chinese
virtual void SetSize( /// @brief 修改大小
Size const& size virtual void SetSize(Size const& size);
);
// 修改大小 /// \~chinese
void SetSize( /// @brief 修改大小
float width, void SetSize(float width, float height);
float height
);
// 设置透明度 /// \~chinese
// 默认为 1.0, 范围 [0, 1] /// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
virtual void SetOpacity( virtual void SetOpacity(float opacity);
float opacity
);
// 启用或禁用级联透明度 /// \~chinese
void SetCascadeOpacityEnabled( /// @brief 启用或禁用级联透明度
bool enabled void SetCascadeOpacityEnabled(bool enabled);
);
// 设置二维仿射变换 /// \~chinese
void SetTransform( /// @brief 设置二维仿射变换
Transform const& transform void SetTransform(Transform const& transform);
);
// 设置 Z 轴顺序 /// \~chinese
// 默认为 0 /// @brief 设置 Z 轴顺序,默认为 0
void SetZOrder( void SetZOrder(int zorder);
int zorder
);
// 是否可响应 (鼠标 Hover | Out | Click 消息) /// \~chinese
// 默认为 false /// @brief 设置角色是否可响应,默认为 false
void SetResponsible( /// @details 可响应的角色会收到鼠标的 Hover | Out | Click 消息
bool enable void SetResponsible(bool enable);
);
// 添加子角色 /// \~chinese
void AddChild( /// @brief 添加子角色
ActorPtr child, void AddChild(ActorPtr child, int zorder = 0);
int zorder = 0
);
// 添加子角色 /// \~chinese
void AddChild( /// @brief 添加子角色
Actor* child, void AddChild(Actor* child, int zorder = 0);
int zorder = 0
);
// 添加多个子角色 /// \~chinese
void AddChildren( /// @brief 添加多个子角色
Vector<ActorPtr> const& children void AddChildren(Vector<ActorPtr> const& children);
);
// 获取名称相同的子角色 /// \~chinese
Actor* GetChild( /// @brief 获取名称相同的子角色
String const& name Actor* GetChild(String const& name) const;
) const;
// 获取所有名称相同的子角色 /// \~chinese
Vector<ActorPtr> GetChildren( /// @brief 获取所有名称相同的子角色
String const& name Vector<ActorPtr> GetChildren(String const& name) const;
) const;
// 获取全部子角色 /// \~chinese
/// @brief 获取全部子角色
Children& GetAllChildren(); Children& GetAllChildren();
// 获取全部子角色 /// \~chinese
/// @brief 获取全部子角色
Children const& GetAllChildren() const; Children const& GetAllChildren() const;
// 移除子角色 /// \~chinese
void RemoveChild( /// @brief 移除子角色
ActorPtr child void RemoveChild(ActorPtr child);
);
// 移除子角色 /// \~chinese
void RemoveChild( /// @brief 移除子角色
Actor* child void RemoveChild(Actor* child);
);
// 移除所有名称相同的子角色 /// \~chinese
void RemoveChildren( /// @brief 移除所有名称相同的子角色
String const& child_name void RemoveChildren(String const& child_name);
);
// 移除所有角色 /// \~chinese
/// @brief 移除所有角色
void RemoveAllChildren(); void RemoveAllChildren();
// 从父角色移除 /// \~chinese
/// @brief 从父角色移除
void RemoveFromParent(); void RemoveFromParent();
// 判断点是否在角色内 /// \~chinese
/// @brief 判断点是否在角色内
virtual bool ContainsPoint(const Point& point) const; virtual bool ContainsPoint(const Point& point) const;
// 暂停角色更新 /// \~chinese
/// @brief 暂停角色更新
void PauseUpdating(); void PauseUpdating();
// 继续角色更新 /// \~chinese
/// @brief 继续角色更新
void ResumeUpdating(); void ResumeUpdating();
// 角色更新是否暂停 /// \~chinese
/// @brief 角色更新是否暂停
bool IsUpdatePausing() const; bool IsUpdatePausing() const;
// 设置更新时的回调函数 /// \~chinese
/// @brief 设置更新时的回调函数
void SetCallbackOnUpdate(UpdateCallback const& cb); void SetCallbackOnUpdate(UpdateCallback const& cb);
// 获取更新时的回调函数 /// \~chinese
/// @brief 获取更新时的回调函数
UpdateCallback GetCallbackOnUpdate() const; UpdateCallback GetCallbackOnUpdate() const;
// 渲染角色边界 /// \~chinese
/// @brief 渲染角色边界
void ShowBorder(bool show); void ShowBorder(bool show);
// 事件分发 /// \~chinese
/// @brief 分发事件
void Dispatch(Event& evt) override; void Dispatch(Event& evt) override;
// 设置默认锚点 /// \~chinese
static void SetDefaultAnchor( /// @brief 设置默认锚点
float anchor_x, static void SetDefaultAnchor(float anchor_x, float anchor_y);
float anchor_y
);
protected: protected:
/// \~chinese
/// @brief 更新自身和所有子角色
virtual void Update(Duration dt); virtual void Update(Duration dt);
/// \~chinese
/// @brief 渲染自身和所有子角色
virtual void Render(RenderTarget* rt); virtual void Render(RenderTarget* rt);
virtual void PrepareRender(RenderTarget* rt); /// \~chinese
/// @brief 绘制自身和所有子角色的边界
virtual void RenderBorder(RenderTarget* rt); virtual void RenderBorder(RenderTarget* rt);
/// \~chinese
/// @brief 检查是否在渲染目标的视区内
virtual bool CheckVisibilty(RenderTarget* rt) const; virtual bool CheckVisibilty(RenderTarget* rt) const;
/// \~chinese
/// @brief 渲染前初始化渲染目标状态,仅当 CheckVisibilty 返回真时调用该函数
virtual void PrepareToRender(RenderTarget* rt);
/// \~chinese
/// @brief 更新自己的二维变换,并通知所有子角色
void UpdateTransform() const; void UpdateTransform() const;
/// \~chinese
/// @brief 更新自己和所有子角色的透明度
void UpdateOpacity(); void UpdateOpacity();
/// \~chinese
/// @brief 将所有子角色按Z轴顺序排序
void Reorder(); void Reorder();
/// \~chinese
/// @brief 设置节点所在舞台
void SetStage(Stage* stage); void SetStage(Stage* stage);
private: private:
@ -421,6 +464,9 @@ namespace kiwano
mutable Matrix3x2 transform_matrix_inverse_; mutable Matrix3x2 transform_matrix_inverse_;
}; };
/** @} */
inline void Actor::OnUpdate(Duration dt) inline void Actor::OnUpdate(Duration dt)
{ {
KGE_NOT_USED(dt); KGE_NOT_USED(dt);

View File

@ -27,11 +27,8 @@ namespace kiwano
Canvas::Canvas() Canvas::Canvas()
: cache_expired_(false) : cache_expired_(false)
, stroke_width_(1.0f) , stroke_width_(1.0f)
, fill_color_(0, 0, 0)
, stroke_color_(Color::White)
, stroke_style_(StrokeStyle::Miter) , stroke_style_(StrokeStyle::Miter)
{ {
Renderer::GetInstance()->CreateTextureRenderTarget(rt_);
} }
Canvas::~Canvas() Canvas::~Canvas()
@ -40,12 +37,14 @@ namespace kiwano
void Canvas::BeginDraw() void Canvas::BeginDraw()
{ {
rt_.BeginDraw(); InitRenderTargetAndBrushs();
rt_->BeginDraw();
} }
void Canvas::EndDraw() void Canvas::EndDraw()
{ {
rt_.EndDraw(); InitRenderTargetAndBrushs();
rt_->EndDraw();
cache_expired_ = true; cache_expired_ = true;
} }
@ -53,58 +52,19 @@ namespace kiwano
{ {
UpdateCache(); 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()); Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight());
rt->DrawTexture(texture_cached_, bitmap_rect, bitmap_rect); rt->DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect);
} }
} }
void Canvas::SetStrokeColor(Color const& color) void Canvas::SetBrush(BrushPtr brush)
{ {
stroke_color_ = color; InitRenderTargetAndBrushs();
} rt_->SetCurrentBrush(brush);
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_;
} }
float Canvas::GetStrokeWidth() const float Canvas::GetStrokeWidth() const
@ -112,45 +72,47 @@ namespace kiwano
return stroke_width_; return stroke_width_;
} }
float Canvas::GetBrushOpacity() const
{
return rt_.GetOpacity();
}
void Canvas::SetBrushTransform(Transform const& transform) void Canvas::SetBrushTransform(Transform const& transform)
{ {
rt_.SetTransform(transform.ToMatrix()); InitRenderTargetAndBrushs();
rt_->SetTransform(transform.ToMatrix());
} }
void Canvas::SetBrushTransform(Matrix3x2 const & transform) void Canvas::SetBrushTransform(Matrix3x2 const & transform)
{ {
rt_.SetTransform(transform); InitRenderTargetAndBrushs();
rt_->SetTransform(transform);
} }
void Canvas::PushLayerArea(LayerArea& area) void Canvas::PushLayerArea(LayerArea& area)
{ {
rt_.PushLayer(area); InitRenderTargetAndBrushs();
rt_->PushLayer(area);
} }
void Canvas::PopLayerArea() void Canvas::PopLayerArea()
{ {
rt_.PopLayer(); InitRenderTargetAndBrushs();
rt_->PopLayer();
} }
void Canvas::PushClipRect(Rect const& clip_rect) void Canvas::PushClipRect(Rect const& clip_rect)
{ {
rt_.PushClipRect(clip_rect); InitRenderTargetAndBrushs();
rt_->PushClipRect(clip_rect);
} }
void Canvas::PopClipRect() void Canvas::PopClipRect()
{ {
rt_.PopClipRect(); InitRenderTargetAndBrushs();
rt_->PopClipRect();
} }
void Canvas::DrawLine(Point const& begin, Point const& end) void Canvas::DrawLine(Point const& begin, Point const& end)
{ {
rt_.SetDefaultBrushColor(stroke_color_); InitRenderTargetAndBrushs();
rt_.DrawLine( rt_->SetCurrentBrush(stroke_brush_);
rt_->DrawLine(
begin, begin,
end, end,
stroke_width_, stroke_width_,
@ -161,8 +123,9 @@ namespace kiwano
void Canvas::DrawCircle(Point const& center, float radius) void Canvas::DrawCircle(Point const& center, float radius)
{ {
rt_.SetDefaultBrushColor(stroke_color_); InitRenderTargetAndBrushs();
rt_.DrawEllipse( rt_->SetCurrentBrush(stroke_brush_);
rt_->DrawEllipse(
center, center,
Vec2(radius, radius), Vec2(radius, radius),
stroke_width_, stroke_width_,
@ -173,8 +136,9 @@ namespace kiwano
void Canvas::DrawEllipse(Point const& center, Vec2 const& radius) void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
{ {
rt_.SetDefaultBrushColor(stroke_color_); InitRenderTargetAndBrushs();
rt_.DrawEllipse( rt_->SetCurrentBrush(stroke_brush_);
rt_->DrawEllipse(
center, center,
radius, radius,
stroke_width_, stroke_width_,
@ -185,8 +149,9 @@ namespace kiwano
void Canvas::DrawRect(Rect const& rect) void Canvas::DrawRect(Rect const& rect)
{ {
rt_.SetDefaultBrushColor(stroke_color_); InitRenderTargetAndBrushs();
rt_.DrawRectangle( rt_->SetCurrentBrush(stroke_brush_);
rt_->DrawRectangle(
rect, rect,
stroke_width_, stroke_width_,
stroke_style_ stroke_style_
@ -196,8 +161,9 @@ namespace kiwano
void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius) void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
{ {
rt_.SetDefaultBrushColor(stroke_color_); InitRenderTargetAndBrushs();
rt_.DrawRoundedRectangle( rt_->SetCurrentBrush(stroke_brush_);
rt_->DrawRoundedRectangle(
rect, rect,
radius, radius,
stroke_width_, stroke_width_,
@ -208,8 +174,9 @@ namespace kiwano
void Canvas::FillCircle(Point const& center, float radius) void Canvas::FillCircle(Point const& center, float radius)
{ {
rt_.SetDefaultBrushColor(fill_color_); InitRenderTargetAndBrushs();
rt_.FillEllipse( rt_->SetCurrentBrush(fill_brush_);
rt_->FillEllipse(
center, center,
Vec2(radius, radius) Vec2(radius, radius)
); );
@ -218,8 +185,9 @@ namespace kiwano
void Canvas::FillEllipse(Point const& center, Vec2 const& radius) void Canvas::FillEllipse(Point const& center, Vec2 const& radius)
{ {
rt_.SetDefaultBrushColor(fill_color_); InitRenderTargetAndBrushs();
rt_.FillEllipse( rt_->SetCurrentBrush(fill_brush_);
rt_->FillEllipse(
center, center,
radius radius
); );
@ -228,8 +196,9 @@ namespace kiwano
void Canvas::FillRect(Rect const& rect) void Canvas::FillRect(Rect const& rect)
{ {
rt_.SetDefaultBrushColor(fill_color_); InitRenderTargetAndBrushs();
rt_.FillRectangle( rt_->SetCurrentBrush(fill_brush_);
rt_->FillRectangle(
rect rect
); );
cache_expired_ = true; cache_expired_ = true;
@ -237,31 +206,40 @@ namespace kiwano
void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius) void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius)
{ {
rt_.SetDefaultBrushColor(fill_color_); InitRenderTargetAndBrushs();
rt_.FillRoundedRectangle( rt_->SetCurrentBrush(fill_brush_);
rt_->FillRoundedRectangle(
rect, rect,
radius radius
); );
cache_expired_ = true; 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; cache_expired_ = true;
} }
} }
void Canvas::DrawText(String const& text, Point const& point) void Canvas::DrawTextLayout(String const& text, Point const& point)
{ {
if (text.empty()) if (text.empty())
return; 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) void Canvas::BeginPath(Point const& begin_pos)
@ -289,15 +267,16 @@ namespace kiwano
geo_sink_.AddBezier(point1, point2, point3); 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); geo_sink_.AddArc(point, radius, rotation, clockwise, is_small);
} }
void Canvas::StrokePath() void Canvas::StrokePath()
{ {
rt_.SetDefaultBrushColor(stroke_color_); InitRenderTargetAndBrushs();
rt_.DrawGeometry( rt_->SetCurrentBrush(stroke_brush_);
rt_->DrawGeometry(
geo_sink_.GetGeometry(), geo_sink_.GetGeometry(),
stroke_width_, stroke_width_,
stroke_style_ stroke_style_
@ -307,8 +286,9 @@ namespace kiwano
void Canvas::FillPath() void Canvas::FillPath()
{ {
rt_.SetDefaultBrushColor(fill_color_); InitRenderTargetAndBrushs();
rt_.FillGeometry( rt_->SetCurrentBrush(fill_brush_);
rt_->FillGeometry(
geo_sink_.GetGeometry() geo_sink_.GetGeometry()
); );
cache_expired_ = true; cache_expired_ = true;
@ -316,28 +296,57 @@ namespace kiwano
void Canvas::Clear() void Canvas::Clear()
{ {
rt_.Clear(); InitRenderTargetAndBrushs();
rt_->Clear();
cache_expired_ = true; cache_expired_ = true;
} }
void Canvas::Clear(Color const& clear_color) void Canvas::Clear(Color const& clear_color)
{ {
rt_.Clear(clear_color); InitRenderTargetAndBrushs();
rt_->Clear(clear_color);
cache_expired_ = true; cache_expired_ = true;
} }
Texture Canvas::ExportToTexture() const TexturePtr Canvas::ExportToTexture() const
{ {
UpdateCache(); UpdateCache();
return texture_cached_; 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 void Canvas::UpdateCache() const
{ {
if (cache_expired_) if (cache_expired_ && rt_)
{ {
texture_cached_ = rt_.GetOutput(); if (!texture_cached_)
cache_expired_ = false; {
texture_cached_ = new Texture;
}
if (rt_->GetOutput(*texture_cached_))
{
cache_expired_ = false;
}
} }
} }

View File

@ -21,235 +21,314 @@
#pragma once #pragma once
#include <kiwano/2d/Actor.h> #include <kiwano/2d/Actor.h>
#include <kiwano/renderer/RenderTarget.h> #include <kiwano/renderer/RenderTarget.h>
#include <kiwano/renderer/GeometrySink.h>
#ifdef DrawText
# undef DrawText
#endif
namespace kiwano namespace kiwano
{ {
// 画布 KGE_DECLARE_SMART_PTR(Canvas);
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Canvas class KGE_API Canvas
: public Actor : public Actor
{ {
public: public:
/// \~chinese
/// @brief 构建空画布
Canvas(); Canvas();
virtual ~Canvas(); virtual ~Canvas();
// 开始绘图 /// \~chinese
/// @brief 开始绘图
void BeginDraw(); void BeginDraw();
// 结束绘图 /// \~chinese
/// @brief 结束绘图
void EndDraw(); void EndDraw();
// 画直线 /// \~chinese
void DrawLine( /// @brief 画线段
Point const& begin, /// @param begin 线段起点
Point const& end /// @param end 线段终点
); void DrawLine(Point const& begin, Point const& end);
// 画圆形边框 /// \~chinese
void DrawCircle( /// @brief 画圆形边框
Point const& center, /// @param center 圆形原点
float radius /// @param radius 圆形半径
); void DrawCircle(Point const& center, float radius);
// 画椭圆形边框 /// \~chinese
void DrawEllipse( /// @brief 画椭圆形边框
Point const& center, /// @param center 椭圆原点
Vec2 const& radius /// @param radius 椭圆半径
); void DrawEllipse(Point const& center, Vec2 const& radius);
// 画矩形边框 /// \~chinese
void DrawRect( /// @brief 画矩形边框
Rect const& rect /// @param rect 矩形
); void DrawRect(Rect const& rect);
// 画圆角矩形边框 /// \~chinese
void DrawRoundedRect( /// @brief 画圆角矩形边框
Rect const& rect, /// @param rect 矩形
Vec2 const& radius /// @param radius 矩形圆角半径
); void DrawRoundedRect(Rect const& rect, Vec2 const& radius);
// 填充圆形 /// \~chinese
void FillCircle( /// @brief 填充圆形
Point const& center, /// @param center 圆形原点
float radius /// @param radius 圆形半径
); void FillCircle(Point const& center, float radius);
// 填充椭圆形 /// \~chinese
void FillEllipse( /// @brief 填充椭圆形
Point const& center, /// @param center 椭圆原点
Vec2 const& radius /// @param radius 椭圆半径
); void FillEllipse(Point const& center, Vec2 const& radius);
// 填充矩形 /// \~chinese
void FillRect( /// @brief 填充矩形
Rect const& rect /// @param rect 矩形
); void FillRect(Rect const& rect);
// 填充圆角矩形 /// \~chinese
void FillRoundedRect( /// @brief 填充圆角矩形
Rect const& rect, /// @param rect 矩形
Vec2 const& radius /// @param radius 矩形圆角半径
); void FillRoundedRect(Rect const& rect, Vec2 const& radius);
// 画图 /// \~chinese
void DrawTexture( /// @brief 绘制纹理
Texture const& texture, /// @param texture 纹理
const Rect* src_rect = nullptr, /// @param src_rect 纹理裁剪区域
const Rect* dest_rect = nullptr /// @param dest_rect 绘制目标区域
); void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
// 画文字 /// \~chinese
void DrawText( /// @brief 绘制文字布局
String const& text, /* 文字 */ /// @param text 文字
Point const& point /* 文字位置 */ /// @param point 绘制文字的位置
); void DrawTextLayout(String const& text, Point const& point);
// 开始绘制路径 /// \~chinese
void BeginPath( /// @brief 绘制文字布局
Point const& begin_pos /* 路径起始点 */ /// @param layout 文字布局
); /// @param point 绘制布局的位置
void DrawTextLayout(TextLayout const& layout, Point const& point);
// 结束路径 /// \~chinese
void EndPath( /// @brief 开始绘制路径
bool closed = true /* 路径是否闭合 */ /// @param begin_pos 路径起始点
); void BeginPath(Point const& begin_pos);
// 添加一条线段 /// \~chinese
void AddLine( /// @brief 结束路径
Point const& point /* 端点 */ /// @param closed 路径是否闭合
); void EndPath(bool closed = false);
// 添加多条线段 /// \~chinese
void AddLines( /// @brief 添加一条线段
Vector<Point> const& points /// @param point 端点
); void AddLine(Point const& point);
// 添加一条三次方贝塞尔曲线 /// \~chinese
void AddBezier( /// @brief 添加多条线段
Point const& point1, /* 贝塞尔曲线的第一个控制点 */ /// @param points 端点集合
Point const& point2, /* 贝塞尔曲线的第二个控制点 */ void AddLines(Vector<Point> const& points);
Point const& point3 /* 贝塞尔曲线的终点 */
);
// 添加弧线 /// \~chinese
void AddArc( /// @brief 添加一条三次方贝塞尔曲线
Point const& point, /* 终点 */ /// @param point1 贝塞尔曲线的第一个控制点
Point const& radius, /* 椭圆半径 */ /// @param point2 贝塞尔曲线的第二个控制点
float rotation, /* 椭圆旋转角度 */ /// @param point3 贝塞尔曲线的终点
bool clockwise = true, /* 顺时针 or 逆时针 */ void AddBezier(Point const& point1, Point const& point2, Point const& point3);
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 StrokePath(); void StrokePath();
// 路径填充 /// \~chinese
/// @brief 以填充的方式绘制路径
void FillPath(); void FillPath();
// 清空画布 /// \~chinese
/// @brief 清空画布
void Clear(); void Clear();
// 清空画布 /// \~chinese
void Clear( /// @brief 清空画布
Color const& clear_color /// @param clear_color 清空颜色
); void Clear(Color const& clear_color);
// 设置填充颜色 /// \~chinese
void SetFillColor( /// @brief 设置填充颜色
Color const& color /// @param color 填充颜色
); void SetFillColor(Color const& color);
// 设置轮廓颜色 /// \~chinese
void SetStrokeColor( /// @brief 设置填充画刷
Color const& color /// @param[in] brush 填充画刷
); void SetFillBrush(BrushPtr brush);
// 设置轮廓宽度 /// \~chinese
void SetStrokeWidth( /// @brief 设置轮廓颜色
float width /// @param color 轮廓颜色
); void SetStrokeColor(Color const& color);
// 设置轮廓样式 /// \~chinese
void SetStrokeStyle( /// @brief 设置轮廓画刷
StrokeStyle stroke_style /// @param[in] brush 轮廓画刷
); void SetStrokeBrush(BrushPtr brush);
// 设置文字字体 /// \~chinese
void SetTextFont( /// @brief 设置轮廓宽度
Font const& font /// @param width 轮廓宽度
); void SetStrokeWidth(float width);
// 设置文字画刷样式 /// \~chinese
void SetTextStyle( /// @brief 设置轮廓样式
TextStyle const& text_style /// @param stroke_style 轮廓样式
); void SetStrokeStyle(StrokeStyle stroke_style);
// 设置画笔透明度 /// \~chinese
void SetBrushOpacity( /// @brief 设置文字画刷样式
float opacity /// @param text_style 文字画刷样式
); void SetTextStyle(TextStyle const& text_style);
// 画笔二维变换 /// \~chinese
void SetBrushTransform( /// @brief 设置画刷
Transform const& transform /// @param[in] brush 画刷
); void SetBrush(BrushPtr brush);
// 画笔二维变换 /// \~chinese
void SetBrushTransform( /// @brief 设置画刷二维变换
Matrix3x2 const& transform /// @param transform 二维变换
); void SetBrushTransform(Transform const& transform);
// 设置图层 /// \~chinese
void PushLayerArea( /// @brief 设置画刷二维变换矩阵
LayerArea& area /// @param transform 二维变换矩阵
); void SetBrushTransform(Matrix3x2 const& transform);
// 弹出图层 /// \~chinese
/// @brief 添加一个图层
/// @param area 图层区域
void PushLayerArea(LayerArea& area);
/// \~chinese
/// @brief 删除最近添加的图层
void PopLayerArea(); void PopLayerArea();
// 设置裁剪区域 /// \~chinese
void PushClipRect( /// @brief 添加一个裁剪区域
Rect const& clip_rect /// @param clip_rect 裁剪矩形
); void PushClipRect(Rect const& clip_rect);
// 弹出裁剪区域 /// \~chinese
/// @brief 删除最近添加的裁剪区域
void PopClipRect(); void PopClipRect();
// 获取填充颜色 /// \~chinese
Color GetFillColor() const; /// @brief 获取轮廓宽度
// 获取轮廓颜色
Color GetStrokeColor() const;
// 获取轮廓宽度
float GetStrokeWidth() const; float GetStrokeWidth() const;
// 获取画笔透明度 /// \~chinese
float GetBrushOpacity() const; /// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
// 导出为图片 /// \~chinese
Texture ExportToTexture() const; /// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const;
/// \~chinese
/// @brief 导出纹理
TexturePtr ExportToTexture() const;
void OnRender(RenderTarget* rt) override; void OnRender(RenderTarget* rt) override;
protected: private:
void InitRenderTargetAndBrushs();
void UpdateCache() const; void UpdateCache() const;
protected: private:
float stroke_width_; float stroke_width_;
Color fill_color_; TextStyle text_style_;
Color stroke_color_; StrokeStyle stroke_style_;
Font text_font_; GeometrySink geo_sink_;
TextStyle text_style_; BrushPtr fill_brush_;
StrokeStyle stroke_style_; BrushPtr stroke_brush_;
GeometrySink geo_sink_;
TextureRenderTarget rt_;
mutable bool cache_expired_; mutable bool cache_expired_;
mutable Texture texture_cached_; 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. // THE SOFTWARE.
#include <kiwano/2d/DebugActor.h> #include <kiwano/2d/DebugActor.h>
#include <kiwano/2d/Text.h>
#include <kiwano/renderer/Renderer.h> #include <kiwano/renderer/Renderer.h>
#include <kiwano/core/Logger.h>
#include <psapi.h> #include <psapi.h>
#pragma comment(lib, "psapi.lib") #pragma comment(lib, "psapi.lib")
@ -31,7 +31,7 @@ namespace kiwano
{ {
class comma_numpunct : public std::numpunct<wchar_t> class comma_numpunct : public std::numpunct<wchar_t>
{ {
protected: private:
virtual wchar_t do_thousands_sep() const override virtual wchar_t do_thousands_sep() const override
{ {
return L','; return L',';
@ -42,32 +42,34 @@ namespace kiwano
return "\03"; return "\03";
} }
}; };
std::locale comma_locale(std::locale(), new comma_numpunct);
} }
DebugActor::DebugActor() DebugActor::DebugActor()
: background_color_(0.0f, 0.0f, 0.0f, 0.7f)
{ {
SetName(L"kiwano-debug-actor"); SetName(L"kiwano-debug-actor");
SetPosition(Point{ 10, 10 }); SetPosition(Point{ 10, 10 });
SetResponsible(true); SetResponsible(true);
SetCascadeOpacityEnabled(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 }); debug_text_->SetPosition(Point{ 10, 10 });
this->AddChild(debug_text_); this->AddChild(debug_text_);
Font font;
font.family = L"Arial";
font.size = 16.f;
font.weight = FontWeight::Normal;
debug_text_->SetFont(font);
TextStyle style; TextStyle style;
style.font_family = L"Arial";
style.font_size = 16.f;
style.font_weight = FontWeight::Normal;
style.line_spacing = 20.f; style.line_spacing = 20.f;
debug_text_->SetStyle(style); debug_text_->SetStyle(style);
debug_text_->SetFillColor(Color::White);
AddListener(event::MouseHover, [=](Event&) { SetOpacity(0.4f); }); AddListener<MouseHoverEvent>([=](Event&) { SetOpacity(0.4f); });
AddListener(event::MouseOut, [=](Event&) { SetOpacity(1.f); }); AddListener<MouseOutEvent>([=](Event&) { SetOpacity(1.f); });
} }
DebugActor::~DebugActor() DebugActor::~DebugActor()
@ -76,9 +78,7 @@ namespace kiwano
void DebugActor::OnRender(RenderTarget* rt) void DebugActor::OnRender(RenderTarget* rt)
{ {
PrepareRender(rt); rt->SetCurrentBrush(background_brush_);
rt->SetDefaultBrushColor(background_color_);
rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f }); rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f });
} }
@ -94,24 +94,21 @@ namespace kiwano
StringStream ss; StringStream ss;
{ // For formatting integers with commas
// For formatting integers with commas (void)ss.imbue(comma_locale);
static std::locale comma_locale(std::locale(), new comma_numpunct);
(void)ss.imbue(comma_locale);
}
ss << "Fps: " << frame_time_.size() << std::endl; ss << "Fps: " << frame_time_.size() << std::endl;
#if defined(KGE_DEBUG) #if defined(KGE_DEBUG)
if (ObjectBase::IsTracingLeaks()) if (ObjectBase::IsTracingLeaks())
{ {
ss << "Objects: " << ObjectBase::__GetTracingObjects().size() << std::endl; ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl;
} }
#endif #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: "; ss << "Memory: ";
{ {
@ -140,4 +137,9 @@ namespace kiwano
} }
} }
bool DebugActor::CheckVisibilty(RenderTarget* rt) const
{
return true;
}
} }

View File

@ -20,9 +20,21 @@
#pragma once #pragma once
#include <kiwano/2d/Actor.h> #include <kiwano/2d/Actor.h>
#include <kiwano/2d/TextActor.h>
#include <kiwano/renderer/Color.h>
#include <kiwano/renderer/Brush.h>
namespace kiwano namespace kiwano
{ {
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API DebugActor class KGE_API DebugActor
: public Actor : public Actor
{ {
@ -36,8 +48,14 @@ namespace kiwano
void OnUpdate(Duration dt) override; void OnUpdate(Duration dt) override;
protected: protected:
Color background_color_; bool CheckVisibilty(RenderTarget* rt) const override;
TextPtr debug_text_;
private:
BrushPtr background_brush_;
TextActorPtr debug_text_;
Vector<Time> frame_time_; 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) bool Frame::Load(String const& file_path)
{ {
Texture texture = TextureCache::GetInstance()->AddOrGetTexture(file_path); TexturePtr texture = TextureCache::instance().AddOrGetTexture(file_path);
if (texture.IsValid()) if (texture->IsValid())
{ {
SetTexture(texture); SetTexture(texture);
return true; return true;
@ -55,8 +40,8 @@ namespace kiwano
bool Frame::Load(Resource const& res) bool Frame::Load(Resource const& res)
{ {
Texture texture = TextureCache::GetInstance()->AddOrGetTexture(res); TexturePtr texture = TextureCache::instance().AddOrGetTexture(res);
if (texture.IsValid()) if (texture->IsValid())
{ {
SetTexture(texture); SetTexture(texture);
return true; return true;
@ -66,9 +51,9 @@ namespace kiwano
void Frame::SetCropRect(Rect const& crop_rect) 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.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_.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); 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; texture_ = texture;
if (texture_.IsValid()) if (texture_->IsValid())
{ {
crop_rect_.left_top.x = crop_rect_.left_top.y = 0; crop_rect_.left_top.x = crop_rect_.left_top.y = 0;
crop_rect_.right_bottom.x = texture_.GetWidth(); crop_rect_.right_bottom.x = texture_->GetWidth();
crop_rect_.right_bottom.y = texture_.GetHeight(); crop_rect_.right_bottom.y = texture_->GetHeight();
} }
} }
} }

View File

@ -24,63 +24,78 @@
namespace kiwano namespace kiwano
{ {
// 帧图像 KGE_DECLARE_SMART_PTR(Frame);
/**
* \~chinese
* @brief
*/
class KGE_API Frame class KGE_API Frame
: public ObjectBase : public ObjectBase
{ {
public: public:
/// \~chinese
/// @brief 构建空图像帧
Frame(); Frame();
explicit Frame( /// \~chinese
String const& file_path /// @brief 加载图像
); /// @param file_path 图像路径
bool Load(String const& file_path);
explicit Frame( /// \~chinese
Resource const& res /// @brief 加载图像
); /// @param res 图像资源
bool Load(Resource const& res);
explicit Frame( /// \~chinese
Texture const& texture /// @brief 裁剪图像帧为矩形
); /// @param crop_rect 裁剪矩形定义
void SetCropRect(Rect const& crop_rect);
bool Load( /// \~chinese
String const& file_path /// @brief 设置纹理
); /// @param texture 纹理
void SetTexture(TexturePtr texture);
bool Load( /// \~chinese
Resource const& res /// @brief 是否有效
); bool IsValid() const;
// 裁剪矩形 /// \~chinese
void SetCropRect( /// @brief 获取宽度
Rect const& crop_rect /* 裁剪矩形 */ float GetWidth() const;
);
// 设置纹理 /// \~chinese
void SetTexture( /// @brief 获取高度
Texture const& texture float GetHeight() const;
);
// 获取宽度 /// \~chinese
float GetWidth() const { return crop_rect_.GetWidth(); } /// @brief 获取大小
Size GetSize() const;
// 获取高度 /// \~chinese
float GetHeight() const { return crop_rect_.GetHeight(); } /// @brief 获取裁剪位置
Point GetCropPoint() const;
// 获取大小 /// \~chinese
Size GetSize() const { return crop_rect_.GetSize(); } /// @brief 获取裁剪矩形
Rect const& GetCropRect() const;
// 获取裁剪位置 /// \~chinese
Point GetCropPoint() const { return crop_rect_.GetLeftTop(); } /// @brief 获取纹理
TexturePtr GetTexture() const;
// 获取裁剪矩形 private:
inline Rect const& GetCropRect() const { return crop_rect_; } TexturePtr texture_;
// 获取纹理
inline Texture const& GetTexture() const { return texture_; }
protected:
Texture texture_;
Rect crop_rect_; 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. // THE SOFTWARE.
#include <kiwano/2d/FrameSequence.h> #include <kiwano/2d/FrameSequence.h>
#include <kiwano/2d/Frame.h>
#include <kiwano/core/Logger.h> #include <kiwano/core/Logger.h>
namespace kiwano namespace kiwano
@ -70,6 +69,11 @@ namespace kiwano
return frames_; return frames_;
} }
size_t FrameSequence::GetFramesCount() const
{
return frames_.size();
}
FrameSequencePtr FrameSequence::Clone() const FrameSequencePtr FrameSequence::Clone() const
{ {
auto frame_seq = new (std::nothrow) FrameSequence; auto frame_seq = new (std::nothrow) FrameSequence;

View File

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

View File

@ -19,7 +19,6 @@
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/2d/GifSprite.h> #include <kiwano/2d/GifSprite.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/renderer/TextureCache.h> #include <kiwano/renderer/TextureCache.h>
#include <kiwano/renderer/Renderer.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) bool GifSprite::Load(String const& file_path)
{ {
GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(file_path); GifImagePtr image = TextureCache::instance().AddOrGetGifImage(file_path);
return Load(texture); return Load(image);
} }
bool GifSprite::Load(Resource const& res) bool GifSprite::Load(Resource const& res)
{ {
GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(res); GifImagePtr image = TextureCache::instance().AddOrGetGifImage(res);
return Load(texture); return Load(image);
} }
bool GifSprite::Load(GifImage gif) bool GifSprite::Load(GifImagePtr gif)
{ {
if (gif.IsValid()) if (gif && gif->IsValid())
{ {
gif_ = gif; gif_ = gif;
@ -71,14 +54,14 @@ namespace kiwano
loop_count_ = 0; loop_count_ = 0;
frame_.disposal_type = GifImage::DisposalType::None; 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(); ComposeNextFrame();
} }
@ -89,11 +72,11 @@ namespace kiwano
void GifSprite::OnRender(RenderTarget* rt) 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); Actor::Update(dt);
if (gif_.IsValid() && animating_) if (gif_ && gif_->IsValid() && animating_)
{ {
frame_elapsed_ += dt; frame_elapsed_ += dt;
if (frame_.delay <= frame_elapsed_) if (frame_.delay <= frame_elapsed_)
@ -113,7 +96,7 @@ namespace kiwano
} }
} }
void GifSprite::SetGifImage(GifImage const& gif) void GifSprite::SetGifImage(GifImagePtr gif)
{ {
gif_ = gif; gif_ = gif;
RestartAnimation(); RestartAnimation();
@ -129,7 +112,10 @@ namespace kiwano
void GifSprite::ComposeNextFrame() void GifSprite::ComposeNextFrame()
{ {
if (frame_rt_.IsValid()) KGE_ASSERT(frame_rt_);
KGE_ASSERT(gif_);
if (frame_rt_->IsValid())
{ {
do do
{ {
@ -137,7 +123,7 @@ namespace kiwano
OverlayNextFrame(); OverlayNextFrame();
} while (frame_.delay.IsZero() && !IsLastFrame()); } while (frame_.delay.IsZero() && !IsLastFrame());
animating_ = (!EndOfAnimation() && gif_.GetFramesCount() > 1); animating_ = (!EndOfAnimation() && gif_->GetFramesCount() > 1);
} }
} }
@ -150,48 +136,51 @@ namespace kiwano
break; break;
case GifImage::DisposalType::Background: case GifImage::DisposalType::Background:
{
ClearCurrentFrameArea(); ClearCurrentFrameArea();
break; break;
}
case GifImage::DisposalType::Previous: case GifImage::DisposalType::Previous:
{
RestoreSavedFrame(); RestoreSavedFrame();
break; break;
} }
default:
ThrowIfFailed(E_FAIL);
}
} }
void GifSprite::OverlayNextFrame() 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) if (frame_.disposal_type == GifImage::DisposalType::Previous)
{ {
SaveComposedFrame(); SaveComposedFrame();
} }
if (frame_rt_.IsValid()) if (frame_rt_->IsValid())
{ {
frame_rt_.BeginDraw(); frame_rt_->BeginDraw();
if (next_index_ == 0) if (next_index_ == 0)
{ {
loop_count_++; loop_count_++;
} }
frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect); if (frame_.texture)
frame_rt_.EndDraw();
Texture frame_to_render = frame_rt_.GetOutput();
if (frame_to_render.IsValid())
{ {
frame_.raw = frame_to_render; frame_rt_->DrawTexture(*frame_.texture, nullptr, &frame_.rect);
next_index_ = (++next_index_) % gif_.GetFramesCount(); }
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() 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(); saved_frame_ = new Texture;
auto prop = D2D1::BitmapProperties(frame_to_be_saved.GetPixelFormat()); frame_rt_->CreateTexture(*saved_frame_, frame_to_be_saved->GetSizeInPixels(), 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);
}
} }
}
if (SUCCEEDED(hr)) saved_frame_->CopyFrom(frame_to_be_saved);
{
saved_frame_.CopyFrom(frame_to_be_saved);
} }
ThrowIfFailed(hr);
} }
void GifSprite::RestoreSavedFrame() 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 (frame_rt_->GetOutput(*frame_to_copy_to))
if (SUCCEEDED(hr))
{ {
frame_to_copy_to.CopyFrom(saved_frame_); frame_to_copy_to->CopyFrom(saved_frame_);
} }
} }
ThrowIfFailed(hr);
} }
void GifSprite::ClearCurrentFrameArea() void GifSprite::ClearCurrentFrameArea()
{ {
frame_rt_.BeginDraw(); KGE_ASSERT(frame_rt_);
frame_rt_->BeginDraw();
frame_rt_.PushClipRect(frame_.rect); frame_rt_->PushClipRect(frame_.rect);
frame_rt_.Clear(); frame_rt_->Clear();
frame_rt_.PopClipRect(); frame_rt_->PopClipRect();
return frame_rt_.EndDraw(); return frame_rt_->EndDraw();
} }
} }

View File

@ -26,93 +26,145 @@
namespace kiwano namespace kiwano
{ {
// GIF 精灵 KGE_DECLARE_SMART_PTR(GifSprite);
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief GIF
*/
class KGE_API GifSprite class KGE_API GifSprite
: public Actor : public Actor
{ {
public: public:
using LoopDoneCallback = Function<void(int)>; /// \~chinese
/// @brief GIF播放循环结束回调
using LoopDoneCallback = Function<void(int /* times */)>;
/// \~chinese
/// @brief GIF播放结束回调
using DoneCallback = Function<void()>; using DoneCallback = Function<void()>;
GifSprite(); GifSprite();
GifSprite( /// \~chinese
String const& file_path /// @brief 加载GIF图片
); /// @param file_path GIF图片路径
bool Load(String const& file_path);
GifSprite( /// \~chinese
Resource const& res /// @brief 加载GIF图片
); /// @param res GIF图片资源
bool Load(Resource const& res);
GifSprite( /// \~chinese
GifImage gif /// @brief 加载GIF图片
); /// @param gif GIF图片
bool Load(GifImagePtr gif);
bool Load( /// \~chinese
String const& file_path /// @brief 设置 GIF 动画循环次数
); void SetLoopCount(int loops);
bool Load( /// \~chinese
Resource const& res /// @brief 设置 GIF 动画每次循环结束回调函数
); void SetLoopDoneCallback(LoopDoneCallback const& cb);
bool Load( /// \~chinese
GifImage gif /// @brief 设置 GIF 动画结束回调函数
); void SetDoneCallback(DoneCallback const& cb);
// 设置 GIF 动画循环次数 /// \~chinese
inline void SetLoopCount(int loops) { total_loop_count_ = loops; } /// @brief 设置 GIF 图像
void SetGifImage(GifImagePtr gif);
// 设置 GIF 动画每次循环结束回调函数 /// \~chinese
inline void SetLoopDoneCallback(LoopDoneCallback const& cb) { loop_cb_ = cb; } /// @brief 重新播放 GIF 动画
// 设置 GIF 动画结束回调函数
inline void SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; }
// 设置 GIF 图像
void SetGifImage(GifImage const& gif);
// 重新播放动画
void RestartAnimation(); 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; void OnRender(RenderTarget* rt) override;
protected: private:
void Update(Duration dt) override; 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(); void ComposeNextFrame();
/// \~chinese
/// @brief 解析当前图像帧
void DisposeCurrentFrame(); void DisposeCurrentFrame();
/// \~chinese
/// @brief 覆盖下一帧
void OverlayNextFrame(); void OverlayNextFrame();
/// \~chinese
/// @brief 保存合成后的图像帧
void SaveComposedFrame(); void SaveComposedFrame();
/// \~chinese
/// @brief 恢复已保存的图像帧
void RestoreSavedFrame(); void RestoreSavedFrame();
/// \~chinese
/// @brief 清空当前图像区域
void ClearCurrentFrameArea(); void ClearCurrentFrameArea();
protected: private:
bool animating_; bool animating_;
int total_loop_count_; int total_loop_count_;
int loop_count_; int loop_count_;
size_t next_index_; size_t next_index_;
Duration frame_elapsed_; Duration frame_elapsed_;
LoopDoneCallback loop_cb_; LoopDoneCallback loop_cb_;
DoneCallback done_cb_; DoneCallback done_cb_;
GifImage gif_; GifImagePtr gif_;
GifImage::Frame frame_; GifImage::Frame frame_;
Texture saved_frame_; TexturePtr saved_frame_;
TextureRenderTarget frame_rt_; 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() Layer::Layer()
: swallow_(false) : 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() Layer::~Layer()
@ -84,50 +74,17 @@ namespace kiwano
void Layer::Render(RenderTarget* rt) void Layer::Render(RenderTarget* rt)
{ {
PrepareRender(rt);
rt->PushLayer(area_); rt->PushLayer(area_);
Actor::Render(rt); Actor::Render(rt);
rt->PopLayer(); rt->PopLayer();
} }
void Layer::HandleMessages(Event& evt) bool Layer::CheckVisibilty(RenderTarget* rt) const
{ {
if (evt.type == event::MouseDown) // Do not need to render Layer
{ return false;
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);
}
} }
} }

View File

@ -20,11 +20,22 @@
#pragma once #pragma once
#include <kiwano/2d/Actor.h> #include <kiwano/2d/Actor.h>
#include <kiwano/2d/..\renderer\LayerArea.h> #include <kiwano/renderer/LayerArea.h>
#include <kiwano/2d/..\renderer\RenderTarget.h> #include <kiwano/renderer/RenderTarget.h>
namespace kiwano namespace kiwano
{ {
KGE_DECLARE_SMART_PTR(Layer);
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Layer class KGE_API Layer
: public Actor : public Actor
{ {
@ -33,49 +44,64 @@ namespace kiwano
virtual ~Layer(); virtual ~Layer();
// 重载下列函数以获取图层事件 /// \~chinese
virtual void OnMouseButtonDown(MouseButton::Value btn, Point const& p) {} /// @brief 是否开启消息吞没
virtual void OnMouseButtonUp(MouseButton::Value btn, Point const& p) {} bool IsSwallowEventsEnabled() const;
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
inline bool IsSwallowEventsEnabled() const { return swallow_; } /// @brief 设置消息吞没功能
/// @param enabled 是否启用
void SetSwallowEvents(bool enabled);
// 吞没消息 /// \~chinese
inline void SetSwallowEvents(bool enabled) { swallow_ = enabled; } /// @brief 设置裁剪区域
/// @param clip_rect 裁剪矩形
// 设置裁剪区域
void SetClipRect(Rect const& clip_rect); void SetClipRect(Rect const& clip_rect);
// 设置图层透明度 /// \~chinese
/// @brief 设置图层透明度
/// @param opacity 透明度
void SetOpacity(float opacity) override; void SetOpacity(float opacity) override;
// 设置几何蒙层 /// \~chinese
/// @brief 设置几何蒙层
/// @param mask 蒙层的几何形状
void SetMaskGeometry(Geometry const& mask); void SetMaskGeometry(Geometry const& mask);
// 设置几何蒙层的二维变换 /// \~chinese
/// @brief 设置几何蒙层的二维变换
/// @param transform 应用于蒙层的二维变换
void SetMaskTransform(Matrix3x2 const& transform); void SetMaskTransform(Matrix3x2 const& transform);
// 设置图层区域 /// \~chinese
inline void SetArea(LayerArea const& area) { area_ = area; } /// @brief 设置图层区域
/// @param area 图层区域属性
void SetArea(LayerArea const& area);
// 获取图层区域 /// \~chinese
inline LayerArea const& GetArea() const { return area_; } /// @brief 获取图层区域
LayerArea const& GetArea() const;
public:
void Dispatch(Event& evt) override; void Dispatch(Event& evt) override;
protected: protected:
void Render(RenderTarget* rt) override; void Render(RenderTarget* rt) override;
void HandleMessages(Event& evt); bool CheckVisibilty(RenderTarget* rt) const override;
protected: private:
bool swallow_; bool swallow_;
LayerArea area_; 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 namespace kiwano
{ {
ShapeActor::ShapeActor() ShapeActor::ShapeActor()
: fill_color_(Color::White) : stroke_width_(1.f)
, stroke_color_(Color(Color::Black, 0))
, stroke_width_(1.f)
, stroke_style_(StrokeStyle::Miter) , stroke_style_(StrokeStyle::Miter)
{ {
} }
ShapeActor::ShapeActor(Geometry const& geometry)
: ShapeActor()
{
SetGeometry(geometry);
}
ShapeActor::~ShapeActor() ShapeActor::~ShapeActor()
{ {
} }
@ -49,7 +41,7 @@ namespace kiwano
Rect ShapeActor::GetBoundingBox() const Rect ShapeActor::GetBoundingBox() const
{ {
if (!geo_) if (!geo_.IsValid())
return Rect{}; return Rect{};
return geo_.GetBoundingBox(GetTransformMatrix()); return geo_.GetBoundingBox(GetTransformMatrix());
@ -57,17 +49,7 @@ namespace kiwano
bool ShapeActor::ContainsPoint(const Point& point) const bool ShapeActor::ContainsPoint(const Point& point) const
{ {
return geo_.ContainsPoint(point, GetTransformMatrix()); return geo_.ContainsPoint(point, &GetTransformMatrix());
}
void ShapeActor::SetFillColor(const Color & color)
{
fill_color_ = color;
}
void ShapeActor::SetStrokeColor(const Color & color)
{
stroke_color_ = color;
} }
void ShapeActor::SetStrokeWidth(float width) void ShapeActor::SetStrokeWidth(float width)
@ -83,7 +65,7 @@ namespace kiwano
void ShapeActor::SetGeometry(Geometry const& geometry) void ShapeActor::SetGeometry(Geometry const& geometry)
{ {
geo_ = geometry; geo_ = geometry;
if (geo_) if (geo_.IsValid())
{ {
bounds_ = geo_.GetBoundingBox(); bounds_ = geo_.GetBoundingBox();
SetSize(bounds_.GetSize()); SetSize(bounds_.GetSize());
@ -97,22 +79,29 @@ namespace kiwano
void ShapeActor::OnRender(RenderTarget* rt) void ShapeActor::OnRender(RenderTarget* rt)
{ {
if (geo_ && CheckVisibilty(rt)) // Create default brush
if (!fill_brush_)
{ {
PrepareRender(rt); fill_brush_ = new Brush;
fill_brush_->SetColor(Color::White);
rt->SetDefaultBrushColor(stroke_color_);
rt->DrawGeometry(
geo_,
stroke_width_ * 2, // twice width for widening
stroke_style_
);
rt->SetDefaultBrushColor(fill_color_);
rt->FillGeometry(
geo_
);
} }
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() LineActor::~LineActor()
{ {
} }
@ -151,11 +135,6 @@ namespace kiwano
{ {
} }
RectActor::RectActor(Size const& size)
{
SetRectSize(size);
}
RectActor::~RectActor() RectActor::~RectActor()
{ {
} }
@ -178,11 +157,6 @@ namespace kiwano
{ {
} }
RoundRectActor::RoundRectActor(Size const& size, Vec2 const& radius)
{
SetRoundedRect(size, radius);
}
RoundRectActor::~RoundRectActor() RoundRectActor::~RoundRectActor()
{ {
} }
@ -217,11 +191,6 @@ namespace kiwano
{ {
} }
CircleActor::CircleActor(float radius)
{
SetRadius(radius);
}
CircleActor::~CircleActor() CircleActor::~CircleActor()
{ {
} }
@ -244,11 +213,6 @@ namespace kiwano
{ {
} }
EllipseActor::EllipseActor(Vec2 const& radius)
{
SetRadius(radius);
}
EllipseActor::~EllipseActor() EllipseActor::~EllipseActor()
{ {
} }
@ -271,11 +235,6 @@ namespace kiwano
{ {
} }
PolygonActor::PolygonActor(Vector<Point> const& points)
{
SetVertices(points);
}
PolygonActor::~PolygonActor() 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); sink_.BeginPath(begin_pos);
} }
void PathActor::EndPath(bool closed) void PathShapeActor::EndPath(bool closed)
{ {
sink_.EndPath(closed); sink_.EndPath(closed);
Geometry geo = sink_.GetGeometry(); Geometry geo = sink_.GetGeometry();
if (geo) if (geo.IsValid())
{ {
SetGeometry(geo); SetGeometry(geo);
} }
} }
void PathActor::AddLine(Point const& point) void PathShapeActor::AddLine(Point const& point)
{ {
sink_.AddLine(point); sink_.AddLine(point);
} }
void PathActor::AddLines(Vector<Point> const& points) void PathShapeActor::AddLines(Vector<Point> const& points)
{ {
sink_.AddLines(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); 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); 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 #pragma once
#include <kiwano/2d/Actor.h> #include <kiwano/2d/Actor.h>
#include <kiwano/renderer/Brush.h>
#include <kiwano/renderer/Geometry.h> #include <kiwano/renderer/Geometry.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/renderer/StrokeStyle.h> #include <kiwano/renderer/StrokeStyle.h>
namespace kiwano 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 class KGE_API ShapeActor
: public Actor : public Actor
{ {
public: public:
/// \~chinese
/// @brief 构造二维形状角色
ShapeActor(); ShapeActor();
ShapeActor(
Geometry const& geometry
);
virtual ~ShapeActor(); virtual ~ShapeActor();
// 获取填充颜色 /// \~chinese
inline Color GetFillColor() const { return fill_color_; } /// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
// 获取线条颜色 /// \~chinese
inline Color GetStrokeColor() const { return stroke_color_; } /// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const;
// 获取线条宽度 /// \~chinese
inline float GetStrokeWidth() const { return stroke_width_; } /// @brief 获取线条宽度
float GetStrokeWidth() const;
// 获取线条样式 /// \~chinese
inline StrokeStyle SetStrokeStyle() const { return stroke_style_; } /// @brief 获取线条样式
StrokeStyle SetStrokeStyle() const;
// 获取形状 /// \~chinese
inline Geometry GetGeometry() const { return geo_; } /// @brief 获取形状
Geometry GetGeometry() const;
// 获取边界 /// \~chinese
/// @brief 获取边界
Rect GetBounds() const override; Rect GetBounds() const override;
// 获取外切包围盒 /// \~chinese
/// @brief 获取外切包围盒
Rect GetBoundingBox() const override; Rect GetBoundingBox() const override;
// 判断点是否在形状内 /// \~chinese
/// @brief 判断点是否在形状内
bool ContainsPoint(const Point& point) const override; bool ContainsPoint(const Point& point) const override;
// 设置填充颜色 /// \~chinese
void SetFillColor(const Color& color); /// @brief 设置填充颜色
/// @param color 填充颜色
void SetFillColor(Color const& color);
// 设置线条颜色 /// \~chinese
void SetStrokeColor(const Color& color); /// @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); void SetStrokeWidth(float width);
// 设置线条样式 /// \~chinese
/// @brief 设置线条样式
void SetStrokeStyle(StrokeStyle stroke_style); void SetStrokeStyle(StrokeStyle stroke_style);
// 设置形状 /// \~chinese
/// @brief 设置几何形状
void SetGeometry(Geometry const& geometry); void SetGeometry(Geometry const& geometry);
void OnRender(RenderTarget* rt) override; void OnRender(RenderTarget* rt) override;
protected: protected:
Color fill_color_; bool CheckVisibilty(RenderTarget* rt) const override;
Color stroke_color_;
private:
BrushPtr fill_brush_;
BrushPtr stroke_brush_;
float stroke_width_; float stroke_width_;
StrokeStyle stroke_style_; StrokeStyle stroke_style_;
Rect bounds_; Rect bounds_;
@ -89,219 +134,269 @@ namespace kiwano
}; };
// 直线角色 /// \~chinese
/// @brief 线段图形角色
class KGE_API LineActor class KGE_API LineActor
: public ShapeActor : public ShapeActor
{ {
public: public:
LineActor(); LineActor();
LineActor(
Point const& begin,
Point const& end
);
virtual ~LineActor(); virtual ~LineActor();
inline Point const& GetBeginPoint() const { return begin_; } /// \~chinese
/// @brief 获取线段起点
inline Point const& GetEndPoint() const { return end_; } Point const& GetBeginPoint() const;
inline void SetBeginPoint(Point const& begin) /// \~chinese
{ /// @brief 获取线段终点
SetLine(begin, end_); Point const& GetEndPoint() const;
}
inline void SetEndPoint(Point const& end) /// \~chinese
{ /// @brief 设置线段起点
SetLine(begin_, end); /// @param begin 线段起点
} void SetBeginPoint(Point const& begin);
void SetLine( /// \~chinese
Point const& begin, /// @brief 设置线段终点
Point const& end /// @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 begin_;
Point end_; Point end_;
}; };
// 矩形角色 /// \~chinese
/// @brief 矩形角色
class KGE_API RectActor class KGE_API RectActor
: public ShapeActor : public ShapeActor
{ {
public: public:
RectActor(); RectActor();
RectActor(
Size const& size
);
virtual ~RectActor(); 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); void SetRectSize(Size const& size);
protected: private:
Size rect_size_; Size rect_size_;
}; };
// 圆角矩形角色
/// \~chinese
/// @brief 圆角矩形角色
class KGE_API RoundRectActor class KGE_API RoundRectActor
: public ShapeActor : public ShapeActor
{ {
public: public:
RoundRectActor(); RoundRectActor();
RoundRectActor(
Size const& size,
Vec2 const& radius
);
virtual ~RoundRectActor(); 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( /// \~chinese
Vec2 const& radius /// @brief 设置圆角半径
); /// @param radius 圆角半径
void SetRadius(Vec2 const& radius);
void SetRectSize( /// \~chinese
Size const& size /// @brief 设置圆角矩形大小
); /// @param size 圆角矩形大小
void SetRectSize(Size const& size);
void SetRoundedRect( /// \~chinese
Size const& size, /// @brief 设置圆角矩形
Vec2 const& radius /// @param size 圆角矩形大小
); /// @param radius 圆角半径
void SetRoundedRect(Size const& size, Vec2 const& radius);
protected: private:
Size rect_size_; Size rect_size_;
Vec2 radius_; Vec2 radius_;
}; };
// 圆形角色 /// \~chinese
/// @brief 圆形角色
class KGE_API CircleActor class KGE_API CircleActor
: public ShapeActor : public ShapeActor
{ {
public: public:
CircleActor(); CircleActor();
CircleActor(
float radius
);
virtual ~CircleActor(); virtual ~CircleActor();
inline float GetRadius() const { return radius_; } /// \~chinese
/// @brief 获取圆形半径
float GetRadius() const;
/// \~chinese
/// @brief 设置圆形半径
/// @param radius 圆形半径
void SetRadius(float radius); void SetRadius(float radius);
protected: private:
float radius_; float radius_;
}; };
// 椭圆角色 /// \~chinese
/// @brief 椭圆角色
class KGE_API EllipseActor class KGE_API EllipseActor
: public ShapeActor : public ShapeActor
{ {
public: public:
EllipseActor(); EllipseActor();
EllipseActor(
Vec2 const& radius
);
virtual ~EllipseActor(); virtual ~EllipseActor();
Vec2 GetRadius() const { return radius_; } /// \~chinese
/// @brief 获取椭圆半径
Vec2 GetRadius() const;
void SetRadius( /// \~chinese
Vec2 const& radius /// @brief 设置椭圆半径
); /// @param radius 椭圆半径
void SetRadius(Vec2 const& radius);
protected: private:
Vec2 radius_; Vec2 radius_;
}; };
// 多边形角色 /// \~chinese
/// @brief 多边形角色
class KGE_API PolygonActor class KGE_API PolygonActor
: public ShapeActor : public ShapeActor
{ {
public: public:
PolygonActor(); PolygonActor();
PolygonActor(
Vector<Point> const& points
);
virtual ~PolygonActor(); virtual ~PolygonActor();
void SetVertices( /// \~chinese
Vector<Point> const& points /// @brief 设置多边形端点
); /// @param points 多边形端点集合
void SetVertices(Vector<Point> const& points);
}; };
// 路径角色 /// \~chinese
class KGE_API PathActor /// @brief 路径图形角色
class KGE_API PathShapeActor
: public ShapeActor : public ShapeActor
{ {
public: public:
PathActor(); PathShapeActor();
virtual ~PathActor(); virtual ~PathShapeActor();
// 开始添加路径 /// \~chinese
void BeginPath( /// @brief 开始添加路径
Point const& begin_pos = Point{} /* 起始点 */ /// @param begin_pos 起始点
); void BeginPath(Point const& begin_pos = Point());
// 结束路径 /// \~chinese
void EndPath( /// @brief 结束添加路径
bool closed = true /* 路径是否闭合 */ /// @param closed 路径是否闭合
); void EndPath(bool closed = true);
// 添加一条线段 /// \~chinese
void AddLine( /// @brief 添加一条线段
Point const& point /* 端点 */ /// @param point 线段端点
); void AddLine(Point const& point);
// 添加多条线段 /// \~chinese
void AddLines( /// @brief 添加多条线段
Vector<Point> const& points /// @param points 线段端点集合
); void AddLines(Vector<Point> const& points);
// 添加一条三次方贝塞尔曲线 /// \~chinese
void AddBezier( /// @brief 添加一条三次方贝塞尔曲线
Point const& point1, /* 贝塞尔曲线的第一个控制点 */ /// @param point1 贝塞尔曲线的第一个控制点
Point const& point2, /* 贝塞尔曲线的第二个控制点 */ /// @param point2 贝塞尔曲线的第二个控制点
Point const& point3 /* 贝塞尔曲线的终点 */ /// @param point3 贝塞尔曲线的终点
); void AddBezier(Point const& point1, Point const& point2, Point const& point3);
// 添加弧线 /// \~chinese
void AddArc( /// @brief 添加弧线
Point const& point, /* 终点 */ /// @param point 椭圆圆心
Size const& radius, /* 椭圆半径 */ /// @param radius 椭圆半径
float rotation, /* 椭圆旋转角度 */ /// @param rotation 椭圆旋转角度
bool clockwise = true, /* 顺时针 or 逆时针 */ /// @param clockwise 顺时针 or 逆时针
bool is_small = true /* 是否取小于 180° 的弧 */ /// @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(); void ClearPath();
protected: private:
GeometrySink sink_; 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