commit
920256886e
|
|
@ -26,4 +26,6 @@ packages/
|
|||
!*.lib
|
||||
|
||||
# Resources bin
|
||||
*.aps
|
||||
*.aps
|
||||
|
||||
docs/
|
||||
|
|
@ -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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -185,4 +185,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -102,4 +102,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -102,4 +102,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -94,4 +94,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kiwano-physics", "kiwano-ph
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libStackWalker", "3rd-party\StackWalker\libStackWalker.vcxproj", "{3A3948DC-9865-46B3-B7B9-7E5572704ED2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtinyxml2", "3rd-party\tinyxml2\libtinyxml2.vcxproj", "{AB47E875-85E5-4105-A71E-88930EAAB910}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libimgui", "3rd-party\imgui\libimgui.vcxproj", "{7FA1E56D-62AC-47D1-97D1-40B302724198}"
|
||||
|
|
@ -47,10 +45,10 @@ Global
|
|||
{A7062ED8-8910-48A5-A3BC-C1612672571F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.Build.0 = Release|Win32
|
||||
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Release|Win32.Build.0 = Release|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.Build.0 = Release|Win32
|
||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Release|Win32.ActiveCfg = Release|Win32
|
||||
|
|
@ -67,16 +65,11 @@ Global
|
|||
{0CBA9295-F14D-4966-A7C4-1DD68158176C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.Build.0 = Release|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{3A3948DC-9865-46B3-B7B9-7E5572704ED2} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||
{AB47E875-85E5-4105-A71E-88930EAAB910} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||
{7FA1E56D-62AC-47D1-97D1-40B302724198} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||
{A9ABACC7-75A1-46BA-8E48-4105346D9719} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\kiwano-audio\audio-modules.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\libraries.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\AudioEngine.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\kiwano-audio.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\Sound.h" />
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano-audio\audio-modules.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\libraries.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\AudioEngine.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\Sound.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\SoundPlayer.cpp" />
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
|
|
@ -108,4 +108,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\kiwano-audio\kiwano-audio.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\AudioEngine.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\audio-modules.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\Sound.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\SoundPlayer.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\Transcoder.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-audio\libraries.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano-audio\AudioEngine.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\audio-modules.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\Sound.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\SoundPlayer.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\Transcoder.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-audio\libraries.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
|
|
@ -110,4 +110,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
|
|
@ -106,4 +106,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\kiwano-physics\Body.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\ContactEdge.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\ContactEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\helper.h" />
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\ContactEdge.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\ContactEvent.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\Joint.cpp" />
|
||||
|
|
@ -44,7 +46,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\ContactEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano-physics\ContactEdge.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
|
||||
|
|
@ -19,5 +20,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\ContactEvent.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano-physics\ContactEdge.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -11,24 +11,16 @@
|
|||
<ClInclude Include="..\..\src\kiwano\2d\action\Animation.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Frame.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\GifSprite.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Event.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\common.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\Event.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\win32\ComPtr.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\win32\helper.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\any.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\basic_json.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\function.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\common.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\intrusive_list.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\intrusive_ptr.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\noncopyable.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\singleton.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\string.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\common\vector.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\kiwano.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\config.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\macros.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\include-forwards.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Canvas.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\DebugActor.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\FrameSequence.h" />
|
||||
|
|
@ -37,8 +29,7 @@
|
|||
<ClInclude Include="..\..\src\kiwano\2d\Actor.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Stage.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Sprite.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Text.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\TextStyle.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Transform.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Transition.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\AsyncTask.h" />
|
||||
|
|
@ -48,7 +39,7 @@
|
|||
<ClInclude Include="..\..\src\kiwano\core\keys.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Logger.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\ObjectBase.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\RefCounter.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Resource.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\SmartPtr.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Timer.h" />
|
||||
|
|
@ -66,15 +57,18 @@
|
|||
<ClInclude Include="..\..\src\kiwano\platform\Director.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\Input.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\modules.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\Window.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\Brush.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\Color.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\Font.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\FontCollection.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\Geometry.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\GifImage.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\StrokeStyle.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\Texture.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\TextureCache.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\LayerArea.h" />
|
||||
|
|
@ -86,6 +80,7 @@
|
|||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3DDeviceResourcesBase.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\TextRenderer.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\ui\Button.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\ui\Menu.h" />
|
||||
|
|
@ -111,17 +106,21 @@
|
|||
<ClCompile Include="..\..\src\kiwano\2d\Actor.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Stage.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Sprite.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Text.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\AsyncTask.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Component.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Event.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\EventDispatcher.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\EventListener.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\KeyEvent.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\MouseEvent.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\WindowEvent.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Library.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Logger.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\TimerManager.cpp" />
|
||||
|
|
@ -130,13 +129,14 @@
|
|||
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\platform\Input.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\platform\modules.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\Font.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\FontCollection.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\Geometry.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\GifImage.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\Texture.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\TextureCache.cpp" />
|
||||
|
|
@ -166,9 +166,6 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\3rd-party\StackWalker\libStackWalker.vcxproj">
|
||||
<Project>{3a3948dc-9865-46b3-b7b9-7e5572704ed2}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\3rd-party\tinyxml2\libtinyxml2.vcxproj">
|
||||
<Project>{ab47e875-85e5-4105-a71e-88930eaab910}</Project>
|
||||
</ProjectReference>
|
||||
|
|
@ -187,7 +184,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@
|
|||
<Filter Include="2d\action">
|
||||
<UniqueIdentifier>{9314f30d-5742-48b6-94e5-e3b4284106f6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="common">
|
||||
<UniqueIdentifier>{86e2d0f2-a9d0-4456-b6a5-d480228bbf82}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="renderer\win32">
|
||||
<UniqueIdentifier>{30333461-e9bc-4709-84bd-ce6e0e1a3079}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="core\win32">
|
||||
<UniqueIdentifier>{192a47a9-9df6-4f40-a7d3-888eb00c53ac}</UniqueIdentifier>
|
||||
<Filter Include="platform\win32">
|
||||
<UniqueIdentifier>{e84dcf9a-e650-473e-8c9c-193804ab9e76}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="core\event">
|
||||
<UniqueIdentifier>{c629aedd-ffb9-4bc1-82c3-f50e77c82e77}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
@ -45,21 +45,12 @@
|
|||
<ClInclude Include="..\..\src\kiwano\2d\Canvas.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\include-forwards.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Layer.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Sprite.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Text.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\TextStyle.hpp">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Transition.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -72,9 +63,6 @@
|
|||
<ClInclude Include="..\..\src\kiwano\core\EventListener.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\RefCounter.hpp">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Resource.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -93,9 +81,6 @@
|
|||
<ClInclude Include="..\..\src\kiwano\platform\Application.h">
|
||||
<Filter>platform</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\platform\modules.h">
|
||||
<Filter>platform</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\config.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\macros.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\math\Vec2.hpp">
|
||||
|
|
@ -150,33 +135,6 @@
|
|||
<ClInclude Include="..\..\src\kiwano\2d\FrameSequence.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\basic_json.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\function.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\intrusive_list.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\intrusive_ptr.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\noncopyable.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\singleton.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\string.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\vector.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\common.h">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\DebugActor.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -240,9 +198,6 @@
|
|||
<ClInclude Include="..\..\src\kiwano\renderer\RenderTarget.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\FontCollection.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Transform.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -267,27 +222,15 @@
|
|||
<ClInclude Include="..\..\src\kiwano\math\scalar.h">
|
||||
<Filter>math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\win32\ComPtr.hpp">
|
||||
<Filter>core\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\win32\helper.h">
|
||||
<Filter>core\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\common\any.hpp">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\utils\UserData.h">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Library.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Event.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h">
|
||||
<Filter>platform</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -303,6 +246,48 @@
|
|||
<ClInclude Include="..\..\src\kiwano\platform\Director.h">
|
||||
<Filter>platform</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h">
|
||||
<Filter>2d</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\common.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h">
|
||||
<Filter>renderer\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp">
|
||||
<Filter>platform\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h">
|
||||
<Filter>platform\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h">
|
||||
<Filter>platform\win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\Event.h">
|
||||
<Filter>core\event</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h">
|
||||
<Filter>core\event</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h">
|
||||
<Filter>core\event</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h">
|
||||
<Filter>core\event</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h">
|
||||
<Filter>core\event</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp">
|
||||
|
|
@ -320,9 +305,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano\2d\Sprite.cpp">
|
||||
<Filter>2d</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Text.cpp">
|
||||
<Filter>2d</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp">
|
||||
<Filter>2d</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -341,9 +323,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp">
|
||||
<Filter>platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\platform\modules.cpp">
|
||||
<Filter>platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -443,9 +422,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano\renderer\RenderTarget.cpp">
|
||||
<Filter>renderer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\FontCollection.cpp">
|
||||
<Filter>renderer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp">
|
||||
<Filter>2d</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -470,9 +446,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano\core\Library.cpp">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\Event.cpp">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp">
|
||||
<Filter>platform</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -485,5 +458,32 @@
|
|||
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp">
|
||||
<Filter>platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp">
|
||||
<Filter>2d</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp">
|
||||
<Filter>renderer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp">
|
||||
<Filter>platform\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp">
|
||||
<Filter>platform\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp">
|
||||
<Filter>core\event</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\KeyEvent.cpp">
|
||||
<Filter>core\event</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\MouseEvent.cpp">
|
||||
<Filter>core\event</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\event\WindowEvent.cpp">
|
||||
<Filter>core\event</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -3,14 +3,19 @@ function Set-FileConfiguration {
|
|||
[string]$filePath
|
||||
)
|
||||
|
||||
$replace = "<DebugInformationFormat>(EditAndContinue|ProgramDatabase)</DebugInformationFormat>"
|
||||
$replaceTo = "<DebugInformationFormat>None</DebugInformationFormat>"
|
||||
$debugInfoReplace = "<DebugInformationFormat>(EditAndContinue|ProgramDatabase)</DebugInformationFormat>"
|
||||
$debugInfoReplaceTo = "<DebugInformationFormat>None</DebugInformationFormat>"
|
||||
|
||||
$optimizationReplace = "<WholeProgramOptimization>true</WholeProgramOptimization>"
|
||||
$optimizationReplaceTo = "<WholeProgramOptimization>false</WholeProgramOptimization>"
|
||||
|
||||
# Create a copy of .vcxproj file
|
||||
Copy-Item -Path $filePath -Destination ($filePath + '.template')
|
||||
|
||||
# Overlay some configurations
|
||||
Get-Content ($filePath + '.template') -Encoding UTF8 | ForEach-Object { $_ -replace $replace, $replaceTo } | Out-File $filePath -Encoding UTF8
|
||||
Get-Content ($filePath + '.template') -Encoding UTF8 | ForEach-Object {
|
||||
( $_ -replace $debugInfoReplace, $debugInfoReplaceTo ) -replace $optimizationReplace, $optimizationReplaceTo
|
||||
} | Out-File $filePath -Encoding UTF8
|
||||
|
||||
# Delete the copy file
|
||||
Remove-Item -Path ($filePath + '.template')
|
||||
|
|
@ -24,3 +29,12 @@ Get-ChildItem -Path 'projects\' -Directory | ForEach-Object {
|
|||
Set-FileConfiguration ($dirPath + '\' + $_)
|
||||
}
|
||||
}
|
||||
|
||||
Get-ChildItem -Path 'projects\3rd-party' -Directory | ForEach-Object {
|
||||
$dirPath = "projects\3rd-party\$($_)"
|
||||
|
||||
# Search all vcxproj files
|
||||
Get-ChildItem -Path $dirPath *.vcxproj -File | ForEach-Object {
|
||||
Set-FileConfiguration ($dirPath + '\' + $_)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -1,32 +1,11 @@
|
|||
// Copyright (c) 2018-2019 Kiwano - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
namespace common
|
||||
namespace oc
|
||||
{
|
||||
|
||||
class bad_any_cast : public std::exception
|
||||
|
|
@ -133,7 +112,7 @@ public:
|
|||
template <typename _Ty>
|
||||
const _Ty* cast_pointer() const noexcept
|
||||
{
|
||||
static_assert(!std::is_void<_Ty>::value, "kiwano::any cannot contain void");
|
||||
static_assert(!std::is_void<_Ty>::value, "oc::any cannot contain void");
|
||||
|
||||
const type_info* const info = typeinfo();
|
||||
if (info && (*info == typeid(std::decay<_Ty>::type)))
|
||||
|
|
@ -519,14 +498,14 @@ _Ty any_cast(any&& a)
|
|||
return static_cast<_Ty>(std::move(*ptr));
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
|
||||
} // namespace kiwano
|
||||
} // namespace oc
|
||||
|
||||
namespace std
|
||||
{
|
||||
inline void swap(kiwano::common::any& lhs, kiwano::common::any& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
inline void swap(oc::any& lhs, oc::any& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cwchar>
|
||||
|
||||
#define OC_ASSERT(EXPR) assert(EXPR)
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
|
@ -1,52 +1,18 @@
|
|||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include "vector/details.h"
|
||||
|
||||
namespace kiwano
|
||||
namespace oc
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
|
||||
|
||||
//
|
||||
// vector_memory_manager<> with memory operations
|
||||
//
|
||||
namespace __vector_details
|
||||
{
|
||||
template<typename _Ty, typename _Alloc, bool _IsClassType = std::is_class<_Ty>::value>
|
||||
struct vector_memory_manager;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// vector<>
|
||||
// Lightweight std::vector<>-like class
|
||||
//
|
||||
template<
|
||||
typename _Ty,
|
||||
typename _Alloc = std::allocator<_Ty>,
|
||||
typename _Manager = __vector_details::vector_memory_manager<_Ty, _Alloc>>
|
||||
template <typename _Ty, typename _Alloc = std::allocator<_Ty>>
|
||||
class vector
|
||||
{
|
||||
public:
|
||||
|
|
@ -59,7 +25,7 @@ public:
|
|||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using allocator_type = typename _Alloc;
|
||||
using manager = typename _Manager;
|
||||
using manager = typename __vector_details::vector_memory_manager<_Ty, _Alloc>;
|
||||
using initializer_list = std::initializer_list<value_type>;
|
||||
|
||||
public:
|
||||
|
|
@ -74,11 +40,11 @@ public:
|
|||
template <typename _Iter>
|
||||
inline vector(_Iter first, _Iter last) : vector() { assign(first, last); }
|
||||
|
||||
inline vector& operator=(const vector& src) { if (&src != this) { resize(src.size_); manager::copy_data(begin(), src.cbegin(), size_); } return (*this); }
|
||||
inline vector& operator=(const vector& src) { if (&src != this) { resize(src.size_); manager::copy_n(begin(), src.cbegin(), size_); } return (*this); }
|
||||
inline vector& operator=(vector&& src) noexcept { swap(src); return *this; }
|
||||
inline vector& operator=(initializer_list list) { if (list.size()) { assign(list.begin(), list.end()); } else clear(); return (*this); }
|
||||
|
||||
inline vector& assign(size_type count, const _Ty& val) { if (count > 0) { resize(count); manager::copy_data(begin(), count, val); } else clear(); return (*this); }
|
||||
inline vector& assign(size_type count, const _Ty& val) { if (count > 0) { resize(count); manager::fill_n(begin(), count, val); } else clear(); return (*this); }
|
||||
inline vector& assign(const vector& src) { return operator=(src); }
|
||||
inline vector& assign(initializer_list list) { return operator=(list); }
|
||||
|
||||
|
|
@ -140,8 +106,8 @@ protected:
|
|||
_Ty* data_;
|
||||
};
|
||||
|
||||
template<typename _Ty, typename _Alloc, typename _Manager>
|
||||
void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val)
|
||||
template<typename _Ty, typename _Alloc>
|
||||
void vector<_Ty, _Alloc>::resize(size_type new_size, const _Ty& val)
|
||||
{
|
||||
if (new_size > size_)
|
||||
{
|
||||
|
|
@ -158,8 +124,8 @@ void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val)
|
|||
size_ = new_size;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _Alloc, typename _Manager>
|
||||
void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity)
|
||||
template<typename _Ty, typename _Alloc>
|
||||
void vector<_Ty, _Alloc>::reserve(size_type new_capacity)
|
||||
{
|
||||
if (new_capacity <= capacity_)
|
||||
return;
|
||||
|
|
@ -167,8 +133,7 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity)
|
|||
auto new_data = manager::allocate(new_capacity);
|
||||
if (data_)
|
||||
{
|
||||
manager::construct(new_data, size_/* only construct needed size */);
|
||||
manager::copy_data(new_data, data_, size_);
|
||||
manager::construct_n(new_data, data_, size_/* only construct needed size */);
|
||||
/* destroy old memory, but not resize */
|
||||
destroy();
|
||||
}
|
||||
|
|
@ -176,9 +141,9 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity)
|
|||
capacity_ = new_capacity;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _Alloc, typename _Manager>
|
||||
typename vector<_Ty, _Alloc, _Manager>::iterator
|
||||
vector<_Ty, _Alloc, _Manager>::erase(const_iterator first, const_iterator last)
|
||||
template<typename _Ty, typename _Alloc>
|
||||
typename vector<_Ty, _Alloc>::iterator
|
||||
vector<_Ty, _Alloc>::erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
const auto off = first - begin();
|
||||
const auto count = last - first;
|
||||
|
|
@ -187,15 +152,15 @@ typename vector<_Ty, _Alloc, _Manager>::iterator
|
|||
{
|
||||
check_offset(off);
|
||||
|
||||
manager::move_data(begin() + off, begin() + off + count, size_ - off - count);
|
||||
manager::move(begin() + off, begin() + off + count, size_ - off - count);
|
||||
resize(size_ - count); // do destruction
|
||||
}
|
||||
return begin() + off;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _Alloc, typename _Manager>
|
||||
typename vector<_Ty, _Alloc, _Manager>::iterator
|
||||
vector<_Ty, _Alloc, _Manager>::insert(const_iterator where, const _Ty& v)
|
||||
template<typename _Ty, typename _Alloc>
|
||||
typename vector<_Ty, _Alloc>::iterator
|
||||
vector<_Ty, _Alloc>::insert(const_iterator where, const _Ty& v)
|
||||
{
|
||||
const auto off = where - begin();
|
||||
const auto insert_at = begin() + off;
|
||||
|
|
@ -203,86 +168,9 @@ typename vector<_Ty, _Alloc, _Manager>::iterator
|
|||
check_offset(off);
|
||||
|
||||
resize(size_ + 1);
|
||||
manager::move_data(insert_at + 1, insert_at, size_ - off - 1);
|
||||
manager::move(insert_at + 1, insert_at, size_ - off - 1);
|
||||
data_[off] = v;
|
||||
return begin() + off;
|
||||
}
|
||||
|
||||
namespace __vector_details
|
||||
{
|
||||
//
|
||||
// vector_memory_manager for common type
|
||||
//
|
||||
template<typename _Ty, typename _Alloc>
|
||||
struct vector_memory_manager<_Ty, _Alloc, false>
|
||||
{
|
||||
using value_type = _Ty;
|
||||
using size_type = size_t;
|
||||
using allocator_type = typename _Alloc;
|
||||
|
||||
static void copy_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; ::memcpy(dest, src, size_type(count) * sizeof(value_type)); }
|
||||
static void copy_data(value_type* dest, size_type count, const value_type& val) { ::memset(dest, int(val), size_type(count) * sizeof(value_type)); }
|
||||
static void move_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; ::memmove(dest, src, size_type(count) * sizeof(value_type)); }
|
||||
|
||||
static value_type* allocate(size_type count) { return get_allocator().allocate(count); }
|
||||
static void deallocate(value_type*& ptr, size_type count) { if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } }
|
||||
|
||||
static void construct(value_type* ptr, size_type count) { }
|
||||
static void construct(value_type* ptr, size_type count, const value_type& val) { while (count) { --count; *(ptr + count) = val; } }
|
||||
static void destroy(value_type* ptr, size_type count) { }
|
||||
|
||||
private:
|
||||
static allocator_type& get_allocator()
|
||||
{
|
||||
static allocator_type allocator_;
|
||||
return allocator_;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// vector_memory_manager for classes
|
||||
//
|
||||
template<typename _Ty, typename _Alloc>
|
||||
struct vector_memory_manager<_Ty, _Alloc, true>
|
||||
{
|
||||
using value_type = _Ty;
|
||||
using size_type = size_t;
|
||||
using allocator_type = typename _Alloc;
|
||||
|
||||
static void copy_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; while (count--) (*dest++) = (*src++); }
|
||||
static void copy_data(value_type* dest, size_type count, const value_type& val) { while (count--) (*dest++) = val; }
|
||||
static void move_data(value_type* dest, const value_type* src, size_type count)
|
||||
{
|
||||
if (src == dest) return;
|
||||
if (dest > src && dest < src + count)
|
||||
{
|
||||
src = src + count - 1;
|
||||
dest = dest + count - 1;
|
||||
while (count--)
|
||||
(*dest--) = (*src--);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (count--)
|
||||
(*dest++) = (*src++);
|
||||
}
|
||||
}
|
||||
|
||||
static value_type* allocate(size_type count) { return get_allocator().allocate(count); }
|
||||
static void deallocate(value_type*& ptr, size_type count) { if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } }
|
||||
|
||||
static void construct(value_type* ptr, size_type count) { construct(ptr, count, value_type()); }
|
||||
static void construct(value_type* ptr, size_type count, const value_type& val) { while (count) get_allocator().construct(ptr + (--count), val); }
|
||||
static void destroy(value_type* ptr, size_type count) { while (count) get_allocator().destroy(ptr + (--count)); }
|
||||
|
||||
private:
|
||||
static allocator_type& get_allocator()
|
||||
{
|
||||
static allocator_type allocator_;
|
||||
return allocator_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace kiwano
|
||||
} // namespace oc
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -18,8 +18,9 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/core/win32/helper.h>
|
||||
#include <kiwano-audio/audio-modules.h>
|
||||
#include <kiwano/platform/win32/helper.h> // win32::ThrowIfFailed
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <kiwano-audio/libraries.h>
|
||||
#include <kiwano-audio/AudioEngine.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -38,13 +39,13 @@ namespace kiwano
|
|||
|
||||
void AudioEngine::SetupComponent()
|
||||
{
|
||||
// KGE_LOG(L"Creating audio resources");
|
||||
KGE_SYS_LOG(L"Creating audio resources");
|
||||
|
||||
HRESULT hr = modules::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||
HRESULT hr = dlls::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = modules::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
hr = dlls::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -52,12 +53,12 @@ namespace kiwano
|
|||
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr);
|
||||
win32::ThrowIfFailed(hr);
|
||||
}
|
||||
|
||||
void AudioEngine::DestroyComponent()
|
||||
{
|
||||
// KGE_LOG(L"Destroying audio resources");
|
||||
KGE_SYS_LOG(L"Destroying audio resources");
|
||||
|
||||
if (mastering_voice_)
|
||||
{
|
||||
|
|
@ -71,39 +72,54 @@ namespace kiwano
|
|||
x_audio2_ = nullptr;
|
||||
}
|
||||
|
||||
modules::MediaFoundation::Get().MFShutdown();
|
||||
dlls::MediaFoundation::Get().MFShutdown();
|
||||
}
|
||||
|
||||
HRESULT AudioEngine::CreateVoice(IXAudio2SourceVoice** voice, const Transcoder::Buffer& buffer)
|
||||
bool AudioEngine::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
||||
{
|
||||
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
||||
|
||||
if (voice == nullptr)
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (buffer.format == nullptr)
|
||||
hr = E_INVALIDARG;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
IXAudio2SourceVoice* voice = nullptr;
|
||||
hr = x_audio2_->CreateSourceVoice(&voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IXAudio2SourceVoice* old = sound.GetXAudio2Voice();
|
||||
if (old)
|
||||
{
|
||||
old->DestroyVoice();
|
||||
old = nullptr;
|
||||
}
|
||||
|
||||
sound.SetXAudio2Voice(voice);
|
||||
}
|
||||
}
|
||||
|
||||
if (*voice)
|
||||
{
|
||||
(*voice)->DestroyVoice();
|
||||
(*voice) = nullptr;
|
||||
}
|
||||
|
||||
return x_audio2_->CreateSourceVoice(voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
win32::WarnIfFailed(hr);
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
void AudioEngine::Open()
|
||||
{
|
||||
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
||||
|
||||
x_audio2_->StartEngine();
|
||||
if (x_audio2_)
|
||||
x_audio2_->StartEngine();
|
||||
}
|
||||
|
||||
void AudioEngine::Close()
|
||||
{
|
||||
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
||||
|
||||
x_audio2_->StopEngine();
|
||||
if (x_audio2_)
|
||||
x_audio2_->StopEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,47 +19,64 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/common/singleton.hpp>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/Component.h>
|
||||
#include <kiwano/core/win32/ComPtr.hpp>
|
||||
#include <kiwano-audio/Transcoder.h>
|
||||
#include <kiwano-audio/Sound.h>
|
||||
#include <xaudio2.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
/**
|
||||
* \~chinese
|
||||
* \defgroup Audio 音频引擎
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup Audio
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频引擎
|
||||
*/
|
||||
class KGE_API AudioEngine
|
||||
: public Singleton<AudioEngine>
|
||||
, public ComponentBase
|
||||
{
|
||||
KGE_DECLARE_SINGLETON(AudioEngine);
|
||||
friend Singleton<AudioEngine>;
|
||||
|
||||
public:
|
||||
// 开启设备
|
||||
/// \~chinese
|
||||
/// @brief 开启音频设备
|
||||
void Open();
|
||||
|
||||
// 关闭设备
|
||||
/// \~chinese
|
||||
/// @brief 关闭音频设备
|
||||
void Close();
|
||||
|
||||
HRESULT CreateVoice(
|
||||
IXAudio2SourceVoice** voice,
|
||||
const Transcoder::Buffer& buffer
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 从解码器数据缓冲中创建音频对象
|
||||
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
|
||||
|
||||
public:
|
||||
void SetupComponent() override;
|
||||
|
||||
void DestroyComponent() override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
AudioEngine();
|
||||
|
||||
~AudioEngine();
|
||||
|
||||
protected:
|
||||
private:
|
||||
IXAudio2* x_audio2_;
|
||||
IXAudio2MasteringVoice* mastering_voice_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,18 +35,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
Sound::Sound(String const& file_path)
|
||||
: Sound()
|
||||
{
|
||||
Load(file_path);
|
||||
}
|
||||
|
||||
Sound::Sound(Resource const& res)
|
||||
: Sound()
|
||||
{
|
||||
Load(res);
|
||||
}
|
||||
|
||||
Sound::~Sound()
|
||||
{
|
||||
Close();
|
||||
|
|
@ -54,9 +42,9 @@ namespace kiwano
|
|||
|
||||
bool Sound::Load(String const& file_path)
|
||||
{
|
||||
if (!FileSystem::GetInstance()->IsFileExists(file_path))
|
||||
if (!FileSystem::instance().IsFileExists(file_path))
|
||||
{
|
||||
KGE_WARNING_LOG(L"Media file '%s' not found", file_path.c_str());
|
||||
KGE_WARN(L"Media file '%s' not found", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -65,22 +53,18 @@ namespace kiwano
|
|||
Close();
|
||||
}
|
||||
|
||||
String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path);
|
||||
String full_path = FileSystem::instance().GetFullPathForFile(file_path);
|
||||
|
||||
HRESULT hr = transcoder_.LoadMediaFile(full_path);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERROR_LOG(L"Load media file failed with HRESULT of %08X", hr);
|
||||
KGE_ERROR(L"Load media file failed with HRESULT of %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer());
|
||||
if (FAILED(hr))
|
||||
if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer()))
|
||||
{
|
||||
Close();
|
||||
|
||||
KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -96,19 +80,15 @@ namespace kiwano
|
|||
}
|
||||
|
||||
HRESULT hr = transcoder_.LoadMediaResource(res);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERROR_LOG(L"Load media resource failed with HRESULT of %08X", hr);
|
||||
KGE_ERROR(L"Load media resource failed with HRESULT of %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer());
|
||||
if (FAILED(hr))
|
||||
if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer()))
|
||||
{
|
||||
Close();
|
||||
|
||||
KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -116,11 +96,16 @@ namespace kiwano
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Sound::IsValid() const
|
||||
{
|
||||
return voice_ != nullptr;
|
||||
}
|
||||
|
||||
void Sound::Play(int loop_count)
|
||||
{
|
||||
if (!opened_)
|
||||
{
|
||||
KGE_ERROR_LOG(L"Sound must be opened first!");
|
||||
KGE_ERROR(L"Sound must be opened first!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +136,7 @@ namespace kiwano
|
|||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERROR_LOG(L"Submitting source buffer failed with HRESULT of %08X", hr);
|
||||
KGE_ERROR(L"Submitting source buffer failed with HRESULT of %08X", hr);
|
||||
}
|
||||
|
||||
playing_ = SUCCEEDED(hr);
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/common/intrusive_ptr.hpp>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||
#include <kiwano-audio/Transcoder.h>
|
||||
#include <xaudio2.h>
|
||||
|
||||
|
|
@ -29,68 +29,100 @@ namespace kiwano
|
|||
{
|
||||
namespace audio
|
||||
{
|
||||
class AudioEngine;
|
||||
|
||||
KGE_DECLARE_SMART_PTR(Sound);
|
||||
|
||||
/**
|
||||
* \addtogroup Audio
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频
|
||||
*/
|
||||
class KGE_API Sound
|
||||
: public ObjectBase
|
||||
{
|
||||
friend class AudioEngine;
|
||||
|
||||
public:
|
||||
Sound();
|
||||
|
||||
Sound(
|
||||
String const& file_path /* 本地音频文件 */
|
||||
);
|
||||
|
||||
Sound(
|
||||
Resource const& res /* 音乐资源 */
|
||||
);
|
||||
|
||||
virtual ~Sound();
|
||||
|
||||
// 打开本地音频文件
|
||||
bool Load(
|
||||
String const& file_path
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 打开本地音频文件
|
||||
/// @param res 本地音频文件路径
|
||||
bool Load(String const& file_path);
|
||||
|
||||
// 打开音乐资源
|
||||
bool Load(
|
||||
Resource const& res /* 音乐资源 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 打开音频资源
|
||||
/// @param res 音频资源
|
||||
bool Load(Resource const& res);
|
||||
|
||||
// 播放
|
||||
void Play(
|
||||
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 是否有效
|
||||
bool IsValid() const;
|
||||
|
||||
// 暂停
|
||||
/// \~chinese
|
||||
/// @brief 播放
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
void Play(int loop_count = 0);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 暂停
|
||||
void Pause();
|
||||
|
||||
// 继续
|
||||
/// \~chinese
|
||||
/// @brief 继续
|
||||
void Resume();
|
||||
|
||||
// 停止
|
||||
/// \~chinese
|
||||
/// @brief 停止
|
||||
void Stop();
|
||||
|
||||
// 关闭并回收资源
|
||||
/// \~chinese
|
||||
/// @brief 关闭并销毁资源
|
||||
void Close();
|
||||
|
||||
// 是否正在播放
|
||||
/// \~chinese
|
||||
/// @brief 是否正在播放
|
||||
bool IsPlaying() const;
|
||||
|
||||
// 获取音量
|
||||
/// \~chinese
|
||||
/// @brief 获取音量
|
||||
float GetVolume() const;
|
||||
|
||||
// 设置音量
|
||||
void SetVolume(
|
||||
float volume /* 1 为原始音量, 大于 1 为放大音量, 0 为最小音量 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置音量
|
||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||
void SetVolume(float volume);
|
||||
|
||||
protected:
|
||||
bool opened_;
|
||||
bool playing_;
|
||||
Transcoder transcoder_;
|
||||
private:
|
||||
IXAudio2SourceVoice* GetXAudio2Voice() const;
|
||||
|
||||
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
|
||||
|
||||
private:
|
||||
bool opened_;
|
||||
bool playing_;
|
||||
Transcoder transcoder_;
|
||||
IXAudio2SourceVoice* voice_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
|
||||
{
|
||||
return voice_;
|
||||
}
|
||||
|
||||
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
|
||||
{
|
||||
voice_ = voice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ namespace kiwano
|
|||
void SoundPlayer::SetVolume(float volume)
|
||||
{
|
||||
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
||||
for (const auto& pair : sound_cache_)
|
||||
for (auto& pair : sound_cache_)
|
||||
{
|
||||
pair.second->SetVolume(volume_);
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ namespace kiwano
|
|||
|
||||
void SoundPlayer::PauseAll()
|
||||
{
|
||||
for (const auto& pair : sound_cache_)
|
||||
for (auto& pair : sound_cache_)
|
||||
{
|
||||
pair.second->Pause();
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ namespace kiwano
|
|||
|
||||
void SoundPlayer::ResumeAll()
|
||||
{
|
||||
for (const auto& pair : sound_cache_)
|
||||
for (auto& pair : sound_cache_)
|
||||
{
|
||||
pair.second->Resume();
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ namespace kiwano
|
|||
|
||||
void SoundPlayer::StopAll()
|
||||
{
|
||||
for (const auto& pair : sound_cache_)
|
||||
for (auto& pair : sound_cache_)
|
||||
{
|
||||
pair.second->Stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/common/intrusive_ptr.hpp>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano-audio/Sound.h>
|
||||
|
||||
|
|
@ -29,76 +28,93 @@ namespace kiwano
|
|||
{
|
||||
KGE_DECLARE_SMART_PTR(SoundPlayer);
|
||||
|
||||
// 音乐播放器
|
||||
/**
|
||||
* \addtogroup Audio
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频播放器
|
||||
*/
|
||||
class KGE_API SoundPlayer
|
||||
: protected ObjectBase
|
||||
: public ObjectBase
|
||||
{
|
||||
public:
|
||||
SoundPlayer();
|
||||
|
||||
~SoundPlayer();
|
||||
|
||||
// 加载本地音频文件, 返回该资源的标识符
|
||||
size_t Load(
|
||||
String const& file_path
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载本地音频文件
|
||||
/// @param file_path 本地音频文件路径
|
||||
/// @return 音频标识符
|
||||
size_t Load(String const& file_path);
|
||||
|
||||
// 加载音乐资源, 返回该资源的标识符
|
||||
size_t Load(
|
||||
Resource const& res /* 音乐资源 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载音频资源
|
||||
/// @param res 音频资源
|
||||
/// @return 音频标识符
|
||||
size_t Load(Resource const& res);
|
||||
|
||||
// 播放音乐
|
||||
void Play(
|
||||
size_t id, /* 标识符 */
|
||||
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 播放音频
|
||||
/// @param id 音频标识符
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
void Play(size_t id, int loop_count = 0);
|
||||
|
||||
// 暂停音乐
|
||||
void Pause(
|
||||
size_t id /* 标识符 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 暂停音频
|
||||
/// @param id 音频标识符
|
||||
void Pause(size_t id);
|
||||
|
||||
// 继续播放音乐
|
||||
void Resume(
|
||||
size_t id /* 标识符 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 继续播放音频
|
||||
/// @param id 音频标识符
|
||||
void Resume(size_t id);
|
||||
|
||||
// 停止音乐
|
||||
void Stop(
|
||||
size_t id /* 标识符 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 停止音频
|
||||
/// @param id 音频标识符
|
||||
void Stop(size_t id);
|
||||
|
||||
// 获取音乐播放状态
|
||||
bool IsPlaying(
|
||||
size_t id /* 标识符 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 获取音频播放状态
|
||||
/// @param id 音频标识符
|
||||
bool IsPlaying(size_t id);
|
||||
|
||||
// 获取音量
|
||||
/// \~chinese
|
||||
/// @brief 获取音量
|
||||
float GetVolume() const;
|
||||
|
||||
// 设置音量
|
||||
void SetVolume(
|
||||
float volume /* 1.0 为原始音量 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置音量
|
||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||
void SetVolume(float volume);
|
||||
|
||||
// 暂停所有音乐
|
||||
/// \~chinese
|
||||
/// @brief 暂停所有音频
|
||||
void PauseAll();
|
||||
|
||||
// 继续播放所有音乐
|
||||
/// \~chinese
|
||||
/// @brief 继续播放所有音频
|
||||
void ResumeAll();
|
||||
|
||||
// 停止所有音乐
|
||||
/// \~chinese
|
||||
/// @brief 停止所有音频
|
||||
void StopAll();
|
||||
|
||||
// 清除缓存
|
||||
/// \~chinese
|
||||
/// @brief 清除缓存
|
||||
void ClearCache();
|
||||
|
||||
protected:
|
||||
private:
|
||||
float volume_;
|
||||
|
||||
using SoundMap = Map<size_t, SoundPtr>;
|
||||
SoundMap sound_cache_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@
|
|||
#endif
|
||||
|
||||
#include <kiwano/macros.h>
|
||||
#include <kiwano/common/string.hpp>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <kiwano/core/win32/ComPtr.hpp>
|
||||
#include <kiwano/platform/modules.h>
|
||||
#include <kiwano-audio/audio-modules.h>
|
||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||
#include <kiwano/platform/win32/libraries.h>
|
||||
#include <kiwano-audio/libraries.h>
|
||||
#include <kiwano-audio/Transcoder.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -76,7 +76,7 @@ namespace kiwano
|
|||
|
||||
ComPtr<IMFSourceReader> reader;
|
||||
|
||||
hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromURL(
|
||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL(
|
||||
file_path.c_str(),
|
||||
nullptr,
|
||||
&reader
|
||||
|
|
@ -101,25 +101,25 @@ namespace kiwano
|
|||
Resource::Data data = res.GetData();
|
||||
if (!data) { return E_FAIL; }
|
||||
|
||||
stream = kiwano::modules::Shlwapi::Get().SHCreateMemStream(
|
||||
stream = win32::dlls::Shlwapi::Get().SHCreateMemStream(
|
||||
static_cast<const BYTE*>(data.buffer),
|
||||
static_cast<uint32_t>(data.size)
|
||||
);
|
||||
|
||||
if (stream == nullptr)
|
||||
{
|
||||
KGE_ERROR_LOG(L"SHCreateMemStream failed");
|
||||
KGE_ERROR(L"SHCreateMemStream failed");
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = modules::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream);
|
||||
hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(
|
||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(
|
||||
byte_stream.get(),
|
||||
nullptr,
|
||||
&reader
|
||||
|
|
@ -142,7 +142,7 @@ namespace kiwano
|
|||
ComPtr<IMFMediaType> partial_type;
|
||||
ComPtr<IMFMediaType> uncompressed_type;
|
||||
|
||||
hr = modules::MediaFoundation::Get().MFCreateMediaType(&partial_type);
|
||||
hr = dlls::MediaFoundation::Get().MFCreateMediaType(&partial_type);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -186,7 +186,7 @@ namespace kiwano
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
uint32_t size = 0;
|
||||
hr = modules::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType(
|
||||
hr = dlls::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType(
|
||||
uncompressed_type.get(),
|
||||
&wave_format_,
|
||||
&size,
|
||||
|
|
@ -225,7 +225,7 @@ namespace kiwano
|
|||
|
||||
if (data == nullptr)
|
||||
{
|
||||
KGE_ERROR_LOG(L"Low memory");
|
||||
KGE_ERROR(L"Low memory");
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -28,41 +28,64 @@ namespace kiwano
|
|||
{
|
||||
namespace audio
|
||||
{
|
||||
class Sound;
|
||||
|
||||
/**
|
||||
* \addtogroup Audio
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频解码器
|
||||
*/
|
||||
class KGE_API Transcoder
|
||||
{
|
||||
friend class Sound;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频数据缓冲
|
||||
*/
|
||||
struct Buffer
|
||||
{
|
||||
BYTE* data;
|
||||
uint32_t size;
|
||||
const WAVEFORMATEX* format;
|
||||
BYTE* data; ///< 音频数据
|
||||
uint32_t size; ///< 音频数据大小
|
||||
const WAVEFORMATEX* format; ///< 音频数据格式
|
||||
};
|
||||
|
||||
Transcoder();
|
||||
|
||||
~Transcoder();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取数据缓冲
|
||||
Buffer GetBuffer() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 清空数据缓冲
|
||||
void ClearBuffer();
|
||||
|
||||
HRESULT LoadMediaFile(
|
||||
String const& file_path
|
||||
);
|
||||
private:
|
||||
/// \~chinese
|
||||
/// @brief 解码本地音频文件
|
||||
HRESULT LoadMediaFile(String const& file_path);
|
||||
|
||||
HRESULT LoadMediaResource(
|
||||
Resource const& res
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 解码音频资源
|
||||
HRESULT LoadMediaResource(Resource const& res);
|
||||
|
||||
HRESULT ReadSource(
|
||||
IMFSourceReader* reader
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 读取音频源数据
|
||||
HRESULT ReadSource(IMFSourceReader* reader);
|
||||
|
||||
private:
|
||||
BYTE* wave_data_;
|
||||
uint32_t wave_size_;
|
||||
WAVEFORMATEX* wave_format_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <kiwano-audio/audio-modules.h>
|
||||
#include <kiwano-audio/libraries.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
namespace modules
|
||||
namespace dlls
|
||||
{
|
||||
XAudio2::XAudio2()
|
||||
: xaudio2()
|
||||
|
|
@ -33,9 +33,9 @@ namespace kiwano
|
|||
{
|
||||
const auto xaudio2_dll_names =
|
||||
{
|
||||
L"xaudio2_9.dll", // for Windows 10
|
||||
L"xaudio2_8.dll", // for Windows 8
|
||||
L"xaudio2_7.dll" // for DirectX SDK
|
||||
"xaudio2_9.dll", // for Windows 10
|
||||
"xaudio2_8.dll", // for Windows 8
|
||||
"xaudio2_7.dll" // for DirectX SDK
|
||||
};
|
||||
|
||||
for (const auto& name : xaudio2_dll_names)
|
||||
|
|
@ -48,11 +48,11 @@ namespace kiwano
|
|||
|
||||
if (xaudio2.IsValid())
|
||||
{
|
||||
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>(L"XAudio2Create");
|
||||
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("XAudio2Create");
|
||||
}
|
||||
else
|
||||
{
|
||||
KGE_ERROR_LOG(L"Load xaudio2.dll failed");
|
||||
KGE_ERROR(L"Load xaudio2.dll failed");
|
||||
throw std::runtime_error("Load xaudio2.dll failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -68,28 +68,28 @@ namespace kiwano
|
|||
, MFCreateSourceReaderFromByteStream(nullptr)
|
||||
, MFCreateMFByteStreamOnStream(nullptr)
|
||||
{
|
||||
if (mfplat.Load(L"Mfplat.dll"))
|
||||
if (mfplat.Load("Mfplat.dll"))
|
||||
{
|
||||
MFStartup = mfplat.GetProcess<PFN_MFStartup>(L"MFStartup");
|
||||
MFShutdown = mfplat.GetProcess<PFN_MFShutdown>(L"MFShutdown");
|
||||
MFCreateMediaType = mfplat.GetProcess<PFN_MFCreateMediaType>(L"MFCreateMediaType");
|
||||
MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess<PFN_MFCreateWaveFormatExFromMFMediaType>(L"MFCreateWaveFormatExFromMFMediaType");
|
||||
MFCreateMFByteStreamOnStream = mfplat.GetProcess<PFN_MFCreateMFByteStreamOnStream>(L"MFCreateMFByteStreamOnStream");
|
||||
MFStartup = mfplat.GetProcess<PFN_MFStartup>("MFStartup");
|
||||
MFShutdown = mfplat.GetProcess<PFN_MFShutdown>("MFShutdown");
|
||||
MFCreateMediaType = mfplat.GetProcess<PFN_MFCreateMediaType>("MFCreateMediaType");
|
||||
MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess<PFN_MFCreateWaveFormatExFromMFMediaType>("MFCreateWaveFormatExFromMFMediaType");
|
||||
MFCreateMFByteStreamOnStream = mfplat.GetProcess<PFN_MFCreateMFByteStreamOnStream>("MFCreateMFByteStreamOnStream");
|
||||
}
|
||||
else
|
||||
{
|
||||
KGE_LOG(L"Load Mfplat.dll failed");
|
||||
KGE_ERROR(L"Load Mfplat.dll failed");
|
||||
throw std::runtime_error("Load Mfplat.dll failed");
|
||||
}
|
||||
|
||||
if (mfreadwrite.Load(L"Mfreadwrite.dll"))
|
||||
if (mfreadwrite.Load("Mfreadwrite.dll"))
|
||||
{
|
||||
MFCreateSourceReaderFromURL = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromURL>(L"MFCreateSourceReaderFromURL");
|
||||
MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>(L"MFCreateSourceReaderFromByteStream");
|
||||
MFCreateSourceReaderFromURL = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromURL>("MFCreateSourceReaderFromURL");
|
||||
MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>("MFCreateSourceReaderFromByteStream");
|
||||
}
|
||||
else
|
||||
{
|
||||
KGE_LOG(L"Load Mfreadwrite.dll failed");
|
||||
KGE_ERROR(L"Load Mfreadwrite.dll failed");
|
||||
throw std::runtime_error("Load Mfreadwrite.dll failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -25,11 +25,13 @@
|
|||
#include <mfidl.h>
|
||||
#include <mfreadwrite.h>
|
||||
|
||||
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
namespace modules
|
||||
namespace dlls
|
||||
{
|
||||
class KGE_API XAudio2
|
||||
{
|
||||
|
|
@ -93,3 +95,5 @@ namespace kiwano
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -35,7 +35,7 @@ namespace kiwano
|
|||
|
||||
void ImGuiLayer::OnRender(RenderTarget* rt)
|
||||
{
|
||||
PrepareRender(rt);
|
||||
PrepareToRender(rt);
|
||||
for (const auto& pipeline : pipelines_)
|
||||
{
|
||||
pipeline.second();
|
||||
|
|
|
|||
|
|
@ -27,8 +27,14 @@ namespace kiwano
|
|||
{
|
||||
KGE_DECLARE_SMART_PTR(ImGuiLayer);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief ImGui管道
|
||||
using ImGuiPipeline = Function<void()>;
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief ImGui图层
|
||||
*/
|
||||
class ImGuiLayer
|
||||
: public Layer
|
||||
{
|
||||
|
|
@ -37,24 +43,26 @@ namespace kiwano
|
|||
|
||||
virtual ~ImGuiLayer();
|
||||
|
||||
// Ìí¼Ó ImGui ÔªËØ
|
||||
void AddItem(
|
||||
ImGuiPipeline const& item,
|
||||
String const& name
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加 ImGui 元素
|
||||
/// @param item 管道
|
||||
/// @param name 元素名称
|
||||
void AddItem(ImGuiPipeline const& item, String const& name);
|
||||
|
||||
// ÒÆ³ý ImGui ÔªËØ
|
||||
void RemoveItem(
|
||||
String const& name
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 移除 ImGui 元素
|
||||
/// @param name 元素名称
|
||||
void RemoveItem(String const& name);
|
||||
|
||||
// 移除所有元素
|
||||
/// \~chinese
|
||||
/// @brief 移除所有元素
|
||||
void RemoveAllItems();
|
||||
|
||||
public:
|
||||
void OnRender(RenderTarget* rt) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
Map<String, ImGuiPipeline> pipelines_;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (C) 2019 Nomango
|
||||
|
||||
#include <kiwano/common/common.h>
|
||||
#include <kiwano/common/Function.hpp>
|
||||
#include <kiwano/common/intrusive_ptr.hpp>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/platform/Window.h>
|
||||
#include <kiwano/platform/Input.h>
|
||||
#include <kiwano/renderer/Renderer.h>
|
||||
|
|
@ -45,9 +43,9 @@ namespace kiwano
|
|||
//ImGui::StyleColorsClassic();
|
||||
|
||||
// Setup Platform/Renderer bindings
|
||||
Init(Window::GetInstance()->GetHandle());
|
||||
Init(Window::instance().GetHandle());
|
||||
|
||||
target_window_ = Renderer::GetInstance()->GetTargetWindow();
|
||||
target_window_ = Renderer::instance().GetTargetWindow();
|
||||
}
|
||||
|
||||
void ImGuiModule::DestroyComponent()
|
||||
|
|
@ -64,9 +62,9 @@ namespace kiwano
|
|||
io.DeltaTime = dt.Seconds();
|
||||
|
||||
// Read keyboard modifiers inputs
|
||||
io.KeyCtrl = Input::GetInstance()->IsDown(KeyCode::Ctrl);
|
||||
io.KeyShift = Input::GetInstance()->IsDown(KeyCode::Shift);
|
||||
io.KeyAlt = Input::GetInstance()->IsDown(KeyCode::Alt);
|
||||
io.KeyCtrl = Input::instance().IsDown(KeyCode::Ctrl);
|
||||
io.KeyShift = Input::instance().IsDown(KeyCode::Shift);
|
||||
io.KeyAlt = Input::instance().IsDown(KeyCode::Alt);
|
||||
io.KeySuper = false;
|
||||
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
||||
|
||||
|
|
@ -106,7 +104,7 @@ namespace kiwano
|
|||
io.KeyMap[ImGuiKey_Y] = KeyCode::Y;
|
||||
io.KeyMap[ImGuiKey_Z] = KeyCode::Z;
|
||||
|
||||
ImGui_Impl_Init(Renderer::GetInstance());
|
||||
ImGui_Impl_Init(&Renderer::instance());
|
||||
}
|
||||
|
||||
void ImGuiModule::BeforeRender()
|
||||
|
|
@ -213,7 +211,7 @@ namespace kiwano
|
|||
KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
Size display_size = Renderer::GetInstance()->GetOutputSize();
|
||||
Size display_size = Renderer::instance().GetOutputSize();
|
||||
io.DisplaySize = ImVec2(display_size.x, display_size.y);
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
|
@ -238,7 +236,7 @@ namespace kiwano
|
|||
::SetCursorPos(pos.x, pos.y);
|
||||
}
|
||||
|
||||
Point pos = Input::GetInstance()->GetMousePos();
|
||||
Point pos = Input::instance().GetMousePos();
|
||||
io.MousePos = ImVec2(pos.x, pos.y);
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +258,7 @@ namespace kiwano
|
|||
case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break;
|
||||
}
|
||||
|
||||
Window::GetInstance()->SetCursor(cursor);
|
||||
Window::instance().SetCursor(cursor);
|
||||
}
|
||||
void ImGuiModule::UpdateGamepads()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,27 +19,24 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/Component.h>
|
||||
#include <kiwano/common/singleton.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief ImGuiÄ£¿é
|
||||
*/
|
||||
class ImGuiModule
|
||||
: public Singleton<ImGuiModule>
|
||||
, public RenderComponent
|
||||
, public UpdateComponent
|
||||
, public EventComponent
|
||||
{
|
||||
KGE_DECLARE_SINGLETON(ImGuiModule);
|
||||
|
||||
private:
|
||||
void Init(HWND hwnd);
|
||||
|
||||
void NewFrame();
|
||||
|
||||
void Render();
|
||||
friend Singleton<ImGuiModule>;
|
||||
|
||||
public:
|
||||
ImGuiModule();
|
||||
|
|
@ -48,14 +45,21 @@ namespace kiwano
|
|||
|
||||
void DestroyComponent() override;
|
||||
|
||||
void OnUpdate(Duration dt) override;
|
||||
|
||||
void BeforeRender() override;
|
||||
|
||||
void AfterRender() override;
|
||||
|
||||
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
void OnUpdate(Duration dt) override;
|
||||
|
||||
private:
|
||||
void Init(HWND hwnd);
|
||||
|
||||
void NewFrame();
|
||||
|
||||
void Render();
|
||||
|
||||
void UpdateMousePos();
|
||||
|
||||
void UpdateMouseCursor();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
|
||||
|
||||
#if !defined(KGE_USE_DIRECTX10)
|
||||
|
||||
#include <kiwano-imgui/imgui_impl_dx11.h>
|
||||
|
|
@ -27,3 +29,5 @@ inline void ImGui_Impl_InvalidateDeviceObjects() { ImGui_ImplDX10_Invalid
|
|||
inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX10_CreateDeviceObjects(); }
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#pragma once
|
||||
#include <3rd-party/imgui/imgui.h>
|
||||
|
||||
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
|
||||
|
||||
struct ID3D10Device;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
|
||||
|
|
@ -13,3 +15,5 @@ IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
|
|||
// Use if you want to reset your rendering device without losing ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
// dear imgui: Renderer for Kiwano (DirectX11)
|
||||
|
||||
#include <kiwano/core/win32/helper.h>
|
||||
#include <kiwano-imgui/imgui_impl_dx11.h>
|
||||
|
||||
// DirectX
|
||||
|
|
@ -259,9 +258,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
|||
subResource.pSysMem = pixels;
|
||||
subResource.SysMemPitch = desc.Width * 4;
|
||||
subResource.SysMemSlicePitch = 0;
|
||||
kiwano::ThrowIfFailed(
|
||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture)
|
||||
);
|
||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||
|
||||
if (pTexture)
|
||||
{
|
||||
|
|
@ -272,9 +269,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
|||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
kiwano::ThrowIfFailed(
|
||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView)
|
||||
);
|
||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
|
||||
|
||||
pTexture->Release();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#pragma once
|
||||
#include <3rd-party/imgui/imgui.h>
|
||||
|
||||
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
|
||||
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
|
|
@ -14,3 +16,5 @@ IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
|||
// Use if you want to reset your rendering device without losing ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@
|
|||
#include <kiwano-imgui/ImGuiModule.h>
|
||||
|
||||
// ImGui
|
||||
#include <3rd-party/imgui/imgui.h>
|
||||
#include <imgui/imgui.h>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace
|
|||
|
||||
uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp)
|
||||
{
|
||||
common::string* recv_buffer = (common::string*)userp;
|
||||
ByteString* recv_buffer = (ByteString*)userp;
|
||||
uint32_t total = size * nmemb;
|
||||
|
||||
// add data to the end of recv_buffer
|
||||
|
|
@ -46,10 +46,10 @@ namespace
|
|||
return total;
|
||||
}
|
||||
|
||||
common::string convert_to_utf8(common::wstring const& str)
|
||||
ByteString convert_to_utf8(String const& str)
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
||||
common::string result;
|
||||
ByteString result;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -58,15 +58,15 @@ namespace
|
|||
catch (std::range_error&)
|
||||
{
|
||||
// bad conversion
|
||||
result = wide_to_string(str);
|
||||
result = WideToMultiByte(str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
common::wstring convert_from_utf8(common::string const& str)
|
||||
String convert_from_utf8(ByteString const& str)
|
||||
{
|
||||
kiwano::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
||||
common::wstring result;
|
||||
oc::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
||||
String result;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ namespace
|
|||
catch (std::range_error&)
|
||||
{
|
||||
// bad conversion
|
||||
result = string_to_wide(str);
|
||||
result = MultiByteToWide(str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
bool Init(HttpClient* client, Vector<common::string> const& headers, common::string const& url, common::string* response_data, common::string* response_header, char* error_buffer)
|
||||
bool Init(HttpClient* client, Vector<ByteString> const& headers, ByteString const& url, ByteString* response_data, ByteString* response_header, char* error_buffer)
|
||||
{
|
||||
if (!SetOption(CURLOPT_ERRORBUFFER, error_buffer))
|
||||
return false;
|
||||
|
|
@ -170,11 +170,11 @@ namespace
|
|||
public:
|
||||
static inline bool GetRequest(
|
||||
HttpClient* client,
|
||||
Vector<common::string> const& headers,
|
||||
common::string const& url,
|
||||
Vector<ByteString> const& headers,
|
||||
ByteString const& url,
|
||||
long* response_code,
|
||||
common::string* response_data,
|
||||
common::string* response_header,
|
||||
ByteString* response_data,
|
||||
ByteString* response_header,
|
||||
char* error_buffer)
|
||||
{
|
||||
Curl curl;
|
||||
|
|
@ -185,12 +185,12 @@ namespace
|
|||
|
||||
static inline bool PostRequest(
|
||||
HttpClient* client,
|
||||
Vector<common::string> const& headers,
|
||||
common::string const& url,
|
||||
common::string const& request_data,
|
||||
Vector<ByteString> const& headers,
|
||||
ByteString const& url,
|
||||
ByteString const& request_data,
|
||||
long* response_code,
|
||||
common::string* response_data,
|
||||
common::string* response_header,
|
||||
ByteString* response_data,
|
||||
ByteString* response_header,
|
||||
char* error_buffer)
|
||||
{
|
||||
Curl curl;
|
||||
|
|
@ -203,12 +203,12 @@ namespace
|
|||
|
||||
static inline bool PutRequest(
|
||||
HttpClient* client,
|
||||
Vector<common::string> const& headers,
|
||||
common::string const& url,
|
||||
common::string const& request_data,
|
||||
Vector<ByteString> const& headers,
|
||||
ByteString const& url,
|
||||
ByteString const& request_data,
|
||||
long* response_code,
|
||||
common::string* response_data,
|
||||
common::string* response_header,
|
||||
ByteString* response_data,
|
||||
ByteString* response_header,
|
||||
char* error_buffer)
|
||||
{
|
||||
Curl curl;
|
||||
|
|
@ -221,11 +221,11 @@ namespace
|
|||
|
||||
static inline bool DeleteRequest(
|
||||
HttpClient* client,
|
||||
Vector<common::string> const& headers,
|
||||
common::string const& url,
|
||||
Vector<ByteString> const& headers,
|
||||
ByteString const& url,
|
||||
long* response_code,
|
||||
common::string* response_data,
|
||||
common::string* response_header,
|
||||
ByteString* response_data,
|
||||
ByteString* response_header,
|
||||
char* error_buffer)
|
||||
{
|
||||
Curl curl;
|
||||
|
|
@ -307,13 +307,13 @@ namespace kiwano
|
|||
bool ok = false;
|
||||
long response_code = 0;
|
||||
char error_message[256] = { 0 };
|
||||
common::string response_header;
|
||||
common::string response_data;
|
||||
ByteString response_header;
|
||||
ByteString response_data;
|
||||
|
||||
common::string url = convert_to_utf8(request->GetUrl());
|
||||
common::string data = convert_to_utf8(request->GetData());
|
||||
ByteString url = convert_to_utf8(request->GetUrl());
|
||||
ByteString data = convert_to_utf8(request->GetData());
|
||||
|
||||
Vector<common::string> headers;
|
||||
Vector<ByteString> headers;
|
||||
headers.reserve(request->GetHeaders().size());
|
||||
for (const auto& pair : request->GetHeaders())
|
||||
{
|
||||
|
|
@ -335,17 +335,17 @@ namespace kiwano
|
|||
ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
|
||||
break;
|
||||
default:
|
||||
KGE_ERROR_LOG(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported");
|
||||
KGE_ERROR(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported");
|
||||
return;
|
||||
}
|
||||
|
||||
response->SetResponseCode(response_code);
|
||||
response->SetHeader(string_to_wide(response_header));
|
||||
response->SetHeader(MultiByteToWide(response_header));
|
||||
response->SetData(convert_from_utf8(response_data));
|
||||
if (!ok)
|
||||
{
|
||||
response->SetSucceed(false);
|
||||
response->SetError(string_to_wide(error_message));
|
||||
response->SetError(MultiByteToWide(error_message));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/common/common.h>
|
||||
#include <kiwano/common/singleton.hpp>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/Component.h>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
|
@ -29,25 +28,55 @@ namespace kiwano
|
|||
{
|
||||
namespace network
|
||||
{
|
||||
/**
|
||||
* \~chinese
|
||||
* \defgroup Network 网络通信
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup Network
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief HTTP客户端
|
||||
*/
|
||||
class KGE_API HttpClient
|
||||
: public Singleton<HttpClient>
|
||||
, public ComponentBase
|
||||
{
|
||||
KGE_DECLARE_SINGLETON(HttpClient);
|
||||
friend Singleton<HttpClient>;
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 发送HTTP请求
|
||||
/// @param[in] request HTTP请求
|
||||
/// @details 发送请求后,无论结束或失败都将调用请求的响应回调函数
|
||||
void Send(HttpRequestPtr request);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置连接超时时长
|
||||
void SetTimeoutForConnect(Duration timeout);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取连接超时时长
|
||||
Duration GetTimeoutForConnect() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置读取超时时长
|
||||
void SetTimeoutForRead(Duration timeout);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取读取超时时长
|
||||
Duration GetTimeoutForRead() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置SSL证书地址
|
||||
void SetSSLVerification(String const& root_certificate_path);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取SSL证书地址
|
||||
String const& GetSSLVerification() const;
|
||||
|
||||
public:
|
||||
|
|
@ -60,10 +89,7 @@ namespace kiwano
|
|||
|
||||
void NetworkThread();
|
||||
|
||||
void Perform(
|
||||
HttpRequestPtr request,
|
||||
HttpResponsePtr response
|
||||
);
|
||||
void Perform(HttpRequestPtr request, HttpResponsePtr response);
|
||||
|
||||
void DispatchResponseCallback();
|
||||
|
||||
|
|
@ -82,6 +108,8 @@ namespace kiwano
|
|||
std::condition_variable_any sleep_condition_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
inline void HttpClient::SetTimeoutForConnect(Duration timeout)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/common/function.hpp>
|
||||
#include <kiwano/common/basic_json.hpp>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/SmartPtr.hpp>
|
||||
|
||||
|
|
@ -32,49 +31,91 @@ namespace kiwano
|
|||
|
||||
KGE_DECLARE_SMART_PTR(HttpRequest);
|
||||
|
||||
/**
|
||||
* \addtogroup Network
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief HTTP请求
|
||||
*/
|
||||
class KGE_API HttpRequest
|
||||
: public ObjectBase
|
||||
{
|
||||
public:
|
||||
using ResponseCallback = Function<void(HttpRequest*, HttpResponse*)>;
|
||||
/// \~chinese
|
||||
/// @brief 响应回调函数
|
||||
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 请求类型
|
||||
enum class Type
|
||||
{
|
||||
Unknown,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete
|
||||
Unknown, ///< 未知
|
||||
Get, ///< HTTP GET请求
|
||||
Post, ///< HTTP POST请求
|
||||
Put, ///< HTTP PUT请求
|
||||
Delete ///< HTTP DELETE请求
|
||||
};
|
||||
|
||||
HttpRequest();
|
||||
|
||||
HttpRequest(Type type);
|
||||
|
||||
// 请求地址
|
||||
/// \~chinese
|
||||
/// @brief 设置请求地址
|
||||
void SetUrl(String const& url);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置请求类型
|
||||
void SetType(Type type);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置请求携带的数据
|
||||
void SetData(String const& data);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置请求携带的JSON数据
|
||||
void SetJsonData(Json const& json);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置HTTP头
|
||||
void SetHeaders(Map<String, String> const& headers);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置HTTP头
|
||||
void SetHeader(String const& field, String const& content);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置响应回调函数
|
||||
void SetResponseCallback(ResponseCallback const& callback);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取请求地址
|
||||
String const& GetUrl() const;
|
||||
|
||||
// 请求类型
|
||||
void SetType(Type type);
|
||||
/// \~chinese
|
||||
/// @brief 获取请求类型
|
||||
Type GetType() const;
|
||||
|
||||
// 请求数据
|
||||
void SetData(String const& data);
|
||||
void SetJsonData(Json const& json);
|
||||
/// \~chinese
|
||||
/// @brief 获取请求数据
|
||||
String const& GetData() const;
|
||||
|
||||
// 请求头
|
||||
void SetHeaders(Map<String, String> const& headers);
|
||||
void SetHeader(String const& field, String const& content);
|
||||
/// \~chinese
|
||||
/// @brief 获取HTTP头
|
||||
Map<String, String>& GetHeaders();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取HTTP头
|
||||
String const& GetHeader(String const& header) const;
|
||||
|
||||
// 响应回调
|
||||
void SetResponseCallback(ResponseCallback const& callback);
|
||||
/// \~chinese
|
||||
/// @brief 获取响应回调函数
|
||||
ResponseCallback const& GetResponseCallback() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
Type type_;
|
||||
String url_;
|
||||
String data_;
|
||||
|
|
@ -82,6 +123,8 @@ namespace kiwano
|
|||
ResponseCallback response_cb_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline HttpRequest::HttpRequest() : type_(Type::Unknown) {}
|
||||
|
||||
inline HttpRequest::HttpRequest(Type type) : type_(type) {}
|
||||
|
|
|
|||
|
|
@ -27,36 +27,66 @@ namespace kiwano
|
|||
{
|
||||
KGE_DECLARE_SMART_PTR(HttpResponse);
|
||||
|
||||
/**
|
||||
* \addtogroup Network
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief HTTP响应
|
||||
*/
|
||||
class KGE_API HttpResponse
|
||||
: public ObjectBase
|
||||
{
|
||||
public:
|
||||
HttpResponse(HttpRequestPtr request);
|
||||
|
||||
// 获取请求
|
||||
/// \~chinese
|
||||
/// @brief 获取对应的HTTP请求
|
||||
HttpRequestPtr GetRequest() const;
|
||||
|
||||
// 响应状态
|
||||
/// \~chinese
|
||||
/// @brief 获取响应状态
|
||||
bool IsSucceed() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取HTTP状态码
|
||||
long GetResponseCode() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取响应头
|
||||
String GetHeader() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取响应数据
|
||||
String const& GetData() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取错误信息
|
||||
String const& GetError() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置响应状态
|
||||
void SetSucceed(bool succeed);
|
||||
|
||||
// 响应状态码
|
||||
long GetResponseCode() const;
|
||||
/// \~chinese
|
||||
/// @brief 设置HTTP状态码
|
||||
void SetResponseCode(long response_code);
|
||||
|
||||
// 响应头
|
||||
String GetHeader() const;
|
||||
/// \~chinese
|
||||
/// @brief 设置响应头
|
||||
void SetHeader(String const& response_header);
|
||||
|
||||
// 响应数据
|
||||
String const& GetData() const;
|
||||
/// \~chinese
|
||||
/// @brief 设置响应数据
|
||||
void SetData(String const& response_data);
|
||||
|
||||
// 错误信息
|
||||
String const& GetError() const;
|
||||
/// \~chinese
|
||||
/// @brief 设置错误信息
|
||||
void SetError(String const& error_buffer);
|
||||
|
||||
protected:
|
||||
private:
|
||||
bool succeed_;
|
||||
long response_code_;
|
||||
HttpRequestPtr request_;
|
||||
|
|
@ -66,6 +96,8 @@ namespace kiwano
|
|||
String error_buffer_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline HttpResponse::HttpResponse(HttpRequestPtr request) : request_(request), succeed_(false), response_code_(0) {}
|
||||
|
||||
inline HttpRequestPtr HttpResponse::GetRequest() const { return request_; }
|
||||
|
|
|
|||
|
|
@ -104,8 +104,7 @@ namespace kiwano
|
|||
{
|
||||
if (fixture.GetB2Fixture())
|
||||
{
|
||||
b2Fixture* ptr = const_cast<b2Fixture*>(fixture.GetB2Fixture());
|
||||
body_->DestroyFixture(ptr);
|
||||
body_->DestroyFixture(fixture.GetB2Fixture());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +253,7 @@ namespace kiwano
|
|||
|
||||
void Body::Destroy()
|
||||
{
|
||||
if (world_)
|
||||
if (world_ && body_)
|
||||
{
|
||||
world_->RemoveBody(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <kiwano-physics/helper.h>
|
||||
#include <kiwano-physics/Shape.h>
|
||||
#include <kiwano-physics/Fixture.h>
|
||||
#include <kiwano-physics/Contact.h>
|
||||
#include <kiwano-physics/ContactEdge.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -30,141 +30,284 @@ namespace kiwano
|
|||
{
|
||||
class World;
|
||||
|
||||
// 膠竟
|
||||
KGE_DECLARE_SMART_PTR(Body);
|
||||
|
||||
/**
|
||||
* \addtogroup Physics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物体
|
||||
class KGE_API Body
|
||||
: public virtual RefCounter
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 物体类型
|
||||
enum class Type
|
||||
{
|
||||
Static = 0,
|
||||
Kinematic,
|
||||
Dynamic,
|
||||
Static = 0, ///< 静态物体
|
||||
Kinematic, ///< 动力学物体
|
||||
Dynamic, ///< 动态物体
|
||||
};
|
||||
|
||||
Body();
|
||||
Body(b2Body* body, Actor* actor);
|
||||
Body(World* world, Actor* actor);
|
||||
Body(World* world, ActorPtr actor) : Body(world, actor.get()) {}
|
||||
Body(World* world, ActorPtr actor);
|
||||
virtual ~Body();
|
||||
|
||||
// 놓迦뺏
|
||||
/// \~chinese
|
||||
/// @brief 初始化
|
||||
/// @param[in] world 物理世界
|
||||
/// @param[in] actor 绑定的角色
|
||||
void Init(World* world, Actor* actor);
|
||||
|
||||
// 警속셸야
|
||||
/// \~chinese
|
||||
/// @brief 添加夹具
|
||||
/// @param shape 物体形状
|
||||
/// @param density 物体密度
|
||||
Fixture AddFixture(Shape* shape, const Fixture::Param& param);
|
||||
|
||||
// 警속近榴
|
||||
/// \~chinese
|
||||
/// @brief 添加圆形夹具
|
||||
/// @param radius 圆形半径
|
||||
/// @param density 物体密度
|
||||
Fixture AddCircleShape(float radius, float density = 0.f);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 添加盒形夹具
|
||||
/// @param size 盒大小
|
||||
/// @param density 物体密度
|
||||
Fixture AddBoxShape(Vec2 const& size, float density = 0.f);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 添加多边形夹具
|
||||
/// @param vertexs 多边形端点
|
||||
/// @param density 物体密度
|
||||
Fixture AddPolygonShape(Vector<Point> const& vertexs, float density = 0.f);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 添加线段形夹具
|
||||
/// @param p1 线段起点
|
||||
/// @param p2 线段终点
|
||||
/// @param density 物体密度
|
||||
Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 添加链条形夹具
|
||||
/// @param vertexs 链条端点
|
||||
/// @param loop 是否闭合
|
||||
/// @param density 物体密度
|
||||
Fixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
|
||||
|
||||
// 삿혤셸야
|
||||
Fixture GetFixtureList() const { KGE_ASSERT(body_); return Fixture(body_->GetFixtureList()); }
|
||||
/// \~chinese
|
||||
/// @brief 获取夹具列表
|
||||
FixtureList GetFixtureList() const;
|
||||
|
||||
// 盧뇜셸야
|
||||
/// \~chinese
|
||||
/// @brief 移除夹具
|
||||
void RemoveFixture(Fixture const& fixture);
|
||||
|
||||
// 삿혤쌈뇰긋
|
||||
ContactEdge GetContactList() const { KGE_ASSERT(body_); ContactEdge(body_->GetContactList()); }
|
||||
/// \~chinese
|
||||
/// @brief 获取接触边列表
|
||||
ContactEdgeList GetContactList() const;
|
||||
|
||||
// 잚깎쯤
|
||||
uint16_t GetCategoryBits() const { return category_bits_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取类别码
|
||||
uint16_t GetCategoryBits() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置类别码
|
||||
void SetCategoryBits(uint16_t category_bits);
|
||||
|
||||
// 툭旒拿쯤
|
||||
uint16_t GetMaskBits() const { return mask_bits_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取碰撞掩码
|
||||
uint16_t GetMaskBits() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置碰撞掩码
|
||||
void SetMaskBits(uint16_t mask_bits);
|
||||
|
||||
// 莉乞多
|
||||
int16_t GetGroupIndex() const { return group_index_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取组索引
|
||||
int16_t GetGroupIndex() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置组索引
|
||||
void SetGroupIndex(int16_t index);
|
||||
|
||||
// 旗瘻실똑
|
||||
float GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); }
|
||||
void SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); }
|
||||
/// \~chinese
|
||||
/// @brief 获取旋转角度
|
||||
float GetBodyRotation() const;
|
||||
|
||||
// 貫零
|
||||
/// \~chinese
|
||||
/// @brief 设置旋转角度
|
||||
void SetBodyRotation(float angle);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体位置
|
||||
Point GetBodyPosition() const;
|
||||
void SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); }
|
||||
|
||||
// 貫零뵨旗瘻긴뻣
|
||||
/// \~chinese
|
||||
/// @brief 设置物体位置
|
||||
void SetBodyPosition(Point const& pos);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 位置和旋转变换
|
||||
void SetBodyTransform(Point const& pos, float angle);
|
||||
|
||||
// 醴좆
|
||||
float GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取质量 [kg]
|
||||
float GetMass() const;
|
||||
|
||||
// 발昑
|
||||
float GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取惯性
|
||||
float GetInertia() const;
|
||||
|
||||
// 醴좆鑒앴
|
||||
/// \~chinese
|
||||
/// @brief 获取质量数据
|
||||
/// @param[out] mass 物体质量 [kg]
|
||||
/// @param[out] center 质心位置
|
||||
/// @param[out] inertia 惯性
|
||||
void GetMassData(float* mass, Point* center, float* inertia) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置质量数据
|
||||
/// @param mass 物体质量 [kg]
|
||||
/// @param center 质心位置
|
||||
/// @param inertia 惯性
|
||||
void SetMassData(float mass, Point const& center, float inertia);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 重置质量数据
|
||||
void ResetMassData();
|
||||
|
||||
// 麟깃瘻뻣
|
||||
/// \~chinese
|
||||
/// @brief 获取世界坐标系上的点在物体上的位置
|
||||
Point GetLocalPoint(Point const& world) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体上的点在世界坐标系的位置
|
||||
Point GetWorldPoint(Point const& local) const;
|
||||
|
||||
// 醴懃麟깃
|
||||
/// \~chinese
|
||||
/// @brief 获取物体质心相对于物体的位置
|
||||
Point GetLocalCenter() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体质心位置
|
||||
Point GetWorldCenter() const;
|
||||
|
||||
// 膠竟잚謹
|
||||
Type GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); }
|
||||
void SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast<b2BodyType>(type)); }
|
||||
/// \~chinese
|
||||
/// @brief 获取物体类型
|
||||
Type GetType() const;
|
||||
|
||||
// 路제凜綾
|
||||
float GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); }
|
||||
void SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); }
|
||||
/// \~chinese
|
||||
/// @brief 设置物体类型
|
||||
void SetType(Type type);
|
||||
|
||||
// 嘉제
|
||||
/// \~chinese
|
||||
/// @brief 获取物体受重力的比例
|
||||
float GetGravityScale() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置物体受重力的比例
|
||||
void SetGravityScale(float scale);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 施力
|
||||
/// @param force 力的大小和方向
|
||||
/// @param point 施力点
|
||||
/// @param wake 是否唤醒物体
|
||||
void ApplyForce(Vec2 const& force, Point const& point, bool wake = true);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 给物体中心施力
|
||||
/// @param force 力的大小和方向
|
||||
/// @param wake 是否唤醒物体
|
||||
void ApplyForceToCenter(Vec2 const& force, bool wake = true);
|
||||
|
||||
// 嘉속큉앤
|
||||
void ApplyTorque(float torque, bool wake = true);
|
||||
/// \~chinese
|
||||
/// @brief 施加扭矩
|
||||
/// @param torque 扭矩
|
||||
/// @param wake 是否唤醒物体
|
||||
void ApplyTorque(float torque, bool wake = false);
|
||||
|
||||
// 미땍旗瘻
|
||||
bool IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); }
|
||||
void SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 旋转角度是否固定
|
||||
bool IsIgnoreRotation() const;
|
||||
|
||||
// 綾뎐
|
||||
bool IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); }
|
||||
void SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 设置是否固定旋转角度
|
||||
void SetIgnoreRotation(bool flag);
|
||||
|
||||
// 金추
|
||||
bool IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); }
|
||||
void SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); }
|
||||
bool IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); }
|
||||
void SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 是否是子弹物体
|
||||
bool IsBullet() const;
|
||||
|
||||
// 삶땡榴檄
|
||||
bool IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); }
|
||||
void SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 设置物体是否是子弹物体
|
||||
void SetBullet(bool flag);
|
||||
|
||||
Actor* GetActor() const { return actor_; }
|
||||
void SetActor(Actor* actor) { actor_ = actor; }
|
||||
/// \~chinese
|
||||
/// @brief 是否处于唤醒状态
|
||||
bool IsAwake() const;
|
||||
|
||||
b2Body* GetB2Body() { return body_; }
|
||||
const b2Body* GetB2Body() const { return body_; }
|
||||
void SetB2Body(b2Body* body);
|
||||
/// \~chinese
|
||||
/// @brief 设置唤醒状态
|
||||
void SetAwake(bool flag);
|
||||
|
||||
World* GetWorld() { return world_; }
|
||||
const World* GetWorld() const { return world_; }
|
||||
/// \~chinese
|
||||
/// @brief 是否启用休眠
|
||||
bool IsSleepingAllowed() const;
|
||||
|
||||
void Destroy();
|
||||
/// \~chinese
|
||||
/// @brief 设置是否允许休眠
|
||||
void SetSleepingAllowed(bool flag);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 是否启用
|
||||
bool IsActive() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置启用状态
|
||||
void SetActive(bool flag);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体所在物理世界
|
||||
World* GetWorld() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体绑定的角色
|
||||
Actor* GetActor() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置物体绑定的角色
|
||||
void SetActor(Actor* actor);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 将物体信息更新到角色
|
||||
void UpdateActor();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 将角色信息更新到物体
|
||||
void UpdateFromActor();
|
||||
|
||||
protected:
|
||||
b2Body* GetB2Body() const;
|
||||
void SetB2Body(b2Body* body);
|
||||
|
||||
private:
|
||||
/// \~chinese
|
||||
/// @brief 销毁物体
|
||||
void UpdateFixtureFilter(b2Fixture* fixture);
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 销毁物体
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
Actor* actor_;
|
||||
World* world_;
|
||||
b2Body* body_;
|
||||
|
|
@ -173,5 +316,65 @@ namespace kiwano
|
|||
uint16_t mask_bits_;
|
||||
int16_t group_index_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline Body::Body(World* world, ActorPtr actor) : Body(world, actor.get()) {}
|
||||
|
||||
inline FixtureList Body::GetFixtureList() const { KGE_ASSERT(body_); return FixtureList(Fixture(body_->GetFixtureList())); }
|
||||
|
||||
inline ContactEdgeList Body::GetContactList() const { KGE_ASSERT(body_); return ContactEdgeList(ContactEdge(body_->GetContactList())); }
|
||||
|
||||
inline uint16_t Body::GetCategoryBits() const { return category_bits_; }
|
||||
|
||||
inline uint16_t Body::GetMaskBits() const { return mask_bits_; }
|
||||
|
||||
inline int16_t Body::GetGroupIndex() const { return group_index_; }
|
||||
|
||||
inline float Body::GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); }
|
||||
|
||||
inline void Body::SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); }
|
||||
|
||||
inline void Body::SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); }
|
||||
|
||||
inline float Body::GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); }
|
||||
|
||||
inline float Body::GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); }
|
||||
|
||||
inline Body::Type Body::GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); }
|
||||
|
||||
inline void Body::SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast<b2BodyType>(type)); }
|
||||
|
||||
inline float Body::GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); }
|
||||
|
||||
inline void Body::SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); }
|
||||
|
||||
inline bool Body::IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); }
|
||||
|
||||
inline void Body::SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); }
|
||||
|
||||
inline bool Body::IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); }
|
||||
|
||||
inline void Body::SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); }
|
||||
|
||||
inline bool Body::IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); }
|
||||
|
||||
inline void Body::SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); }
|
||||
|
||||
inline bool Body::IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); }
|
||||
|
||||
inline void Body::SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); }
|
||||
|
||||
inline bool Body::IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); }
|
||||
|
||||
inline void Body::SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); }
|
||||
|
||||
inline Actor* Body::GetActor() const { return actor_; }
|
||||
|
||||
inline void Body::SetActor(Actor* actor) { actor_ = actor; }
|
||||
|
||||
inline b2Body* Body::GetB2Body() const { return body_; }
|
||||
|
||||
inline World* Body::GetWorld() const { return world_; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,40 +38,26 @@ namespace kiwano
|
|||
SetB2Contact(contact);
|
||||
}
|
||||
|
||||
Contact Contact::GetNext()
|
||||
{
|
||||
KGE_ASSERT(contact_);
|
||||
return Contact(contact_->GetNext());
|
||||
}
|
||||
|
||||
const Contact Contact::GetNext() const
|
||||
{
|
||||
KGE_ASSERT(contact_);
|
||||
return Contact(contact_->GetNext());
|
||||
}
|
||||
|
||||
Fixture Contact::GetFixtureA()
|
||||
Fixture Contact::GetFixtureA() const
|
||||
{
|
||||
KGE_ASSERT(contact_);
|
||||
return Fixture(contact_->GetFixtureA());
|
||||
}
|
||||
|
||||
const Fixture Contact::GetFixtureA() const
|
||||
{
|
||||
KGE_ASSERT(contact_);
|
||||
return Fixture(contact_->GetFixtureA());
|
||||
}
|
||||
|
||||
Fixture Contact::GetFixtureB()
|
||||
Fixture Contact::GetFixtureB() const
|
||||
{
|
||||
KGE_ASSERT(contact_);
|
||||
return Fixture(contact_->GetFixtureB());
|
||||
}
|
||||
|
||||
const Fixture Contact::GetFixtureB() const
|
||||
Body* Contact::GetBodyA() const
|
||||
{
|
||||
KGE_ASSERT(contact_);
|
||||
return Fixture(contact_->GetFixtureB());
|
||||
return GetFixtureA().GetBody();
|
||||
}
|
||||
|
||||
Body* Contact::GetBodyB() const
|
||||
{
|
||||
return GetFixtureB().GetBody();
|
||||
}
|
||||
|
||||
void Contact::SetTangentSpeed(float speed)
|
||||
|
|
@ -100,17 +86,5 @@ namespace kiwano
|
|||
return world->World2Stage(contact_->GetTangentSpeed());
|
||||
}
|
||||
|
||||
|
||||
ContactEdge::ContactEdge()
|
||||
: edge_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ContactEdge::ContactEdge(b2ContactEdge* edge)
|
||||
: ContactEdge()
|
||||
{
|
||||
SetB2ContactEdge(edge);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,85 +28,223 @@ namespace kiwano
|
|||
{
|
||||
class Body;
|
||||
|
||||
// 接触
|
||||
/**
|
||||
* \addtogroup Physics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物理接触
|
||||
class KGE_API Contact
|
||||
{
|
||||
public:
|
||||
Contact();
|
||||
Contact(b2Contact* contact);
|
||||
|
||||
// 是否是接触
|
||||
bool IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); }
|
||||
|
||||
// 启用或禁用 (仅作用于一个时间步)
|
||||
void SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); }
|
||||
bool IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); }
|
||||
/// \~chinese
|
||||
/// @brief 是否有效
|
||||
bool IsValid() const;
|
||||
|
||||
// 获取下一接触
|
||||
Contact GetNext();
|
||||
const Contact GetNext() const;
|
||||
/// \~chinese
|
||||
/// @brief 是否是接触
|
||||
bool IsTouching() const;
|
||||
|
||||
// 夹具 A
|
||||
Fixture GetFixtureA();
|
||||
const Fixture GetFixtureA() const;
|
||||
/// \~chinese
|
||||
/// @brief 启用或禁用 (仅作用于一个时间步)
|
||||
void SetEnabled(bool flag);
|
||||
|
||||
// 夹具 B
|
||||
Fixture GetFixtureB();
|
||||
const Fixture GetFixtureB() const;
|
||||
/// \~chinese
|
||||
/// @brief 是否启用
|
||||
bool IsEnabled() const;
|
||||
|
||||
// 摩擦
|
||||
void SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); }
|
||||
float GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); }
|
||||
void ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取物体A的夹具
|
||||
Fixture GetFixtureA() const;
|
||||
|
||||
// 弹性恢复
|
||||
void SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); }
|
||||
float GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); }
|
||||
void ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取物体B的夹具
|
||||
Fixture GetFixtureB() const;
|
||||
|
||||
// 切线速度
|
||||
/// \~chinese
|
||||
/// @brief 获取物体A
|
||||
Body* GetBodyA() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体B
|
||||
Body* GetBodyB() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置摩擦力
|
||||
void SetFriction(float friction);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取摩擦力
|
||||
float GetFriction() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 重置摩擦力
|
||||
void ResetFriction();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置弹性恢复
|
||||
void SetRestitution(float restitution);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取弹性恢复
|
||||
float GetRestitution() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 重置弹性恢复
|
||||
void ResetRestitution();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置切线速度
|
||||
void SetTangentSpeed(float speed);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取切线速度
|
||||
float GetTangentSpeed() const;
|
||||
|
||||
b2Contact* GetB2Contact() { return contact_; }
|
||||
const b2Contact* GetB2Contact() const { return contact_; }
|
||||
void SetB2Contact(b2Contact* contact) { contact_ = contact; }
|
||||
b2Contact* GetB2Contact() const;
|
||||
void SetB2Contact(b2Contact* contact);
|
||||
|
||||
protected:
|
||||
bool operator== (const Contact& rhs) const;
|
||||
bool operator!= (const Contact& rhs) const;
|
||||
|
||||
private:
|
||||
b2Contact* contact_;
|
||||
};
|
||||
|
||||
|
||||
// 接触边
|
||||
class KGE_API ContactEdge
|
||||
/// \~chinese
|
||||
/// @brief 物理接触列表
|
||||
class ContactList
|
||||
: public List<Contact>
|
||||
{
|
||||
template <typename _Ty>
|
||||
class IteratorImpl
|
||||
: public std::iterator<std::forward_iterator_tag, _Ty>
|
||||
{
|
||||
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
|
||||
|
||||
public:
|
||||
IteratorImpl(const _Ty& elem)
|
||||
: elem_(elem)
|
||||
{
|
||||
}
|
||||
|
||||
inline typename herit::reference operator*() const
|
||||
{
|
||||
return const_cast<typename herit::reference>(elem_);
|
||||
}
|
||||
|
||||
inline typename herit::pointer operator->() const
|
||||
{
|
||||
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
||||
}
|
||||
|
||||
inline IteratorImpl& operator++()
|
||||
{
|
||||
elem_ = elem_.GetB2Contact()->GetNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline IteratorImpl operator++(int)
|
||||
{
|
||||
IteratorImpl old = *this;
|
||||
operator++();
|
||||
return old;
|
||||
}
|
||||
|
||||
inline bool operator== (const IteratorImpl& rhs) const
|
||||
{
|
||||
return elem_ == rhs.elem_;
|
||||
}
|
||||
|
||||
inline bool operator!= (const IteratorImpl& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
_Ty elem_;
|
||||
};
|
||||
|
||||
public:
|
||||
ContactEdge();
|
||||
ContactEdge(b2ContactEdge* edge);
|
||||
using value_type = Contact;
|
||||
using iterator = IteratorImpl<value_type>;
|
||||
using const_iterator = IteratorImpl<const value_type>;
|
||||
|
||||
// 获取接触物体
|
||||
Body* GetOtherBody() { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
|
||||
const Body* GetOtherBody() const { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
|
||||
inline ContactList()
|
||||
{
|
||||
}
|
||||
|
||||
// 获取接触
|
||||
Contact GetContact() { KGE_ASSERT(edge_); return Contact(edge_->contact); }
|
||||
const Contact GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); }
|
||||
inline ContactList(const value_type& first)
|
||||
: first_(first)
|
||||
{
|
||||
}
|
||||
|
||||
// 获取上一接触边
|
||||
ContactEdge GetPrev() { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); }
|
||||
const ContactEdge GetPrev() const { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); }
|
||||
inline const value_type& front() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
// 获取下一接触边
|
||||
ContactEdge GetNext() { KGE_ASSERT(edge_); return ContactEdge(edge_->next); }
|
||||
const ContactEdge GetNext() const { KGE_ASSERT(edge_); return ContactEdge(edge_->next); }
|
||||
inline value_type& front()
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
b2ContactEdge* GetB2ContactEdge() { return edge_; }
|
||||
const b2ContactEdge* GetB2ContactEdge() const { return edge_; }
|
||||
void SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; }
|
||||
inline iterator begin()
|
||||
{
|
||||
return iterator(first_);
|
||||
}
|
||||
|
||||
protected:
|
||||
b2ContactEdge* edge_;
|
||||
inline const_iterator begin() const
|
||||
{
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
inline const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(first_);
|
||||
}
|
||||
|
||||
inline iterator end()
|
||||
{
|
||||
return iterator(nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator end() const
|
||||
{
|
||||
return cend();
|
||||
}
|
||||
|
||||
inline const_iterator cend() const
|
||||
{
|
||||
return const_iterator(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
value_type first_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
inline bool Contact::IsValid() const { return contact_ != nullptr;}
|
||||
inline bool Contact::IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); }
|
||||
inline void Contact::SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); }
|
||||
inline bool Contact::IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); }
|
||||
inline void Contact::SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); }
|
||||
inline float Contact::GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); }
|
||||
inline void Contact::ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); }
|
||||
inline void Contact::SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); }
|
||||
inline float Contact::GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); }
|
||||
inline void Contact::ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); }
|
||||
inline b2Contact* Contact::GetB2Contact() const { return contact_; }
|
||||
inline void Contact::SetB2Contact(b2Contact* contact) { contact_ = contact; }
|
||||
inline bool Contact::operator==(const Contact& rhs) const { return contact_ == rhs.contact_; }
|
||||
inline bool Contact::operator!=(const Contact& rhs) const { return contact_ != rhs.contact_; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,23 +18,23 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <3rd-party/StackWalker/StackWalker.h>
|
||||
#include <kiwano-physics/ContactEdge.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
// Display stack trace on exception
|
||||
inline void ThrowIfFailed(HRESULT hr)
|
||||
namespace physics
|
||||
{
|
||||
if (FAILED(hr))
|
||||
|
||||
ContactEdge::ContactEdge()
|
||||
: edge_(nullptr)
|
||||
{
|
||||
KGE_ERROR_LOG(L"Fatal error with HRESULT of %08X", hr);
|
||||
|
||||
StackWalker{}.ShowCallstack();
|
||||
|
||||
static char buffer[1024 + 1];
|
||||
sprintf_s(buffer, "Fatal error with HRESULT of %08X", hr);
|
||||
throw std::runtime_error(buffer);
|
||||
}
|
||||
|
||||
ContactEdge::ContactEdge(b2ContactEdge* edge)
|
||||
: ContactEdge()
|
||||
{
|
||||
SetB2ContactEdge(edge);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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_; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -22,19 +22,10 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace event
|
||||
{
|
||||
EventType event::ContactBegin = EventType(L"ContactBegin");
|
||||
EventType event::ContactEnd = EventType(L"ContactEnd");
|
||||
}
|
||||
|
||||
namespace physics
|
||||
{
|
||||
|
||||
ContactBeginEvent::ContactBeginEvent()
|
||||
: Event(event::ContactBegin)
|
||||
, body_a(nullptr)
|
||||
, body_b(nullptr)
|
||||
: Event(KGE_EVENT(ContactBeginEvent))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -42,14 +33,10 @@ namespace kiwano
|
|||
: ContactBeginEvent()
|
||||
{
|
||||
this->contact = contact;
|
||||
body_a = this->contact.GetFixtureA().GetBody();
|
||||
body_b = this->contact.GetFixtureB().GetBody();
|
||||
}
|
||||
|
||||
ContactEndEvent::ContactEndEvent()
|
||||
: Event(event::ContactEnd)
|
||||
, body_a(nullptr)
|
||||
, body_b(nullptr)
|
||||
: Event(KGE_EVENT(ContactEndEvent))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -57,8 +44,6 @@ namespace kiwano
|
|||
: ContactEndEvent()
|
||||
{
|
||||
this->contact = contact;
|
||||
body_a = this->contact.GetFixtureA().GetBody();
|
||||
body_b = this->contact.GetFixtureB().GetBody();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,37 +26,37 @@ namespace kiwano
|
|||
{
|
||||
namespace physics
|
||||
{
|
||||
// 接触开始事件
|
||||
/**
|
||||
* \addtogroup Events
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物理接触开始事件
|
||||
class KGE_API ContactBeginEvent
|
||||
: public Event
|
||||
{
|
||||
public:
|
||||
Contact contact;
|
||||
Body* body_a;
|
||||
Body* body_b;
|
||||
Contact contact; ///< 产生的接触
|
||||
|
||||
ContactBeginEvent();
|
||||
|
||||
ContactBeginEvent(Contact const& contact);
|
||||
};
|
||||
|
||||
// 接触结束事件
|
||||
/// \~chinese
|
||||
/// @brief 物理接触结束事件
|
||||
class KGE_API ContactEndEvent
|
||||
: public Event
|
||||
{
|
||||
public:
|
||||
Contact contact;
|
||||
Body* body_a;
|
||||
Body* body_b;
|
||||
Contact contact; ///< 产生的接触
|
||||
|
||||
ContactEndEvent();
|
||||
|
||||
ContactEndEvent(Contact const& contact);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace event
|
||||
{
|
||||
extern EventType ContactBegin; // 接触开始
|
||||
extern EventType ContactEnd; // 接触结束
|
||||
/** @} */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,30 +58,18 @@ namespace kiwano
|
|||
}
|
||||
}
|
||||
|
||||
Body* Fixture::GetBody()
|
||||
Body* Fixture::GetBody() const
|
||||
{
|
||||
KGE_ASSERT(fixture_);
|
||||
return static_cast<Body*>(fixture_->GetBody()->GetUserData());
|
||||
}
|
||||
|
||||
const Body* Fixture::GetBody() const
|
||||
{
|
||||
KGE_ASSERT(fixture_);
|
||||
return static_cast<const Body*>(fixture_->GetBody()->GetUserData());
|
||||
}
|
||||
|
||||
Shape Fixture::GetShape() const
|
||||
{
|
||||
KGE_ASSERT(fixture_);
|
||||
return Shape(fixture_->GetShape());
|
||||
}
|
||||
|
||||
Fixture Fixture::GetNext() const
|
||||
{
|
||||
KGE_ASSERT(fixture_);
|
||||
return Fixture(fixture_->GetNext());
|
||||
}
|
||||
|
||||
void Fixture::GetMassData(float* mass, Point* center, float* inertia) const
|
||||
{
|
||||
KGE_ASSERT(fixture_);
|
||||
|
|
|
|||
|
|
@ -28,16 +28,24 @@ namespace kiwano
|
|||
{
|
||||
class Body;
|
||||
|
||||
// 夹具
|
||||
/**
|
||||
* \addtogroup Physics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物理夹具
|
||||
class Fixture
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 夹具参数
|
||||
struct Param
|
||||
{
|
||||
float density = 0.f;
|
||||
float friction = 0.2f;
|
||||
float restitution = 0.f;
|
||||
bool is_sensor = false;
|
||||
float density = 0.f; ///< 密度
|
||||
float friction = 0.2f; ///< 摩擦力
|
||||
float restitution = 0.f; ///< 弹性恢复
|
||||
bool is_sensor = false; ///< 是否是接触传感器
|
||||
|
||||
Param() {}
|
||||
|
||||
|
|
@ -53,46 +61,195 @@ namespace kiwano
|
|||
Fixture(b2Fixture* fixture);
|
||||
Fixture(Body* body, Shape* shape, const Param& param);
|
||||
|
||||
// 物体
|
||||
Body* GetBody();
|
||||
const Body* GetBody() const;
|
||||
/// \~chinese
|
||||
/// @brief 是否有效
|
||||
bool IsValid() const;
|
||||
|
||||
// 形状
|
||||
/// \~chinese
|
||||
/// @brief 获取夹具所在的物体
|
||||
Body* GetBody() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 形状
|
||||
Shape GetShape() const;
|
||||
|
||||
// 下一夹具 (同一物体上)
|
||||
Fixture GetNext() const;
|
||||
/// \~chinese
|
||||
/// @brief 是否是接触传感器
|
||||
bool IsSensor() const;
|
||||
|
||||
// 接触传感器
|
||||
bool IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); }
|
||||
void SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); }
|
||||
/// \~chinese
|
||||
/// @brief 设置夹具是否是接触传感器
|
||||
/// @details 接触传感器只会产生物理接触,而不会影响物体运动
|
||||
void SetSensor(bool sensor);
|
||||
|
||||
// 质量数据
|
||||
/// \~chinese
|
||||
/// @brief 获取夹具的质量数据
|
||||
void GetMassData(float* mass, Point* center, float* inertia) const;
|
||||
|
||||
// 密度
|
||||
float GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); }
|
||||
void SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); }
|
||||
/// \~chinese
|
||||
/// @brief 获取密度
|
||||
float GetDensity() const;
|
||||
|
||||
// 摩擦力
|
||||
float GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); }
|
||||
void SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); }
|
||||
/// \~chinese
|
||||
/// @brief 设置密度
|
||||
void SetDensity(float density);
|
||||
|
||||
// 弹性恢复
|
||||
float GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); }
|
||||
void SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); }
|
||||
/// \~chinese
|
||||
/// @brief 获取摩擦力 [N]
|
||||
float GetFriction() const;
|
||||
|
||||
// 点测试
|
||||
/// \~chinese
|
||||
/// @brief 设置摩擦力 [N]
|
||||
void SetFriction(float friction);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取弹性恢复
|
||||
float GetRestitution() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置弹性恢复
|
||||
void SetRestitution(float restitution);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 点测试
|
||||
bool TestPoint(const Point& p) const;
|
||||
|
||||
bool IsValid() const { return !!fixture_; }
|
||||
b2Fixture* GetB2Fixture() const;
|
||||
void SetB2Fixture(b2Fixture* fixture);
|
||||
|
||||
b2Fixture* GetB2Fixture() { return fixture_; }
|
||||
const b2Fixture* GetB2Fixture() const { return fixture_; }
|
||||
void SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; }
|
||||
bool operator== (const Fixture& rhs) const;
|
||||
bool operator!= (const Fixture& rhs) const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2Fixture* fixture_;
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物理夹具列表
|
||||
class FixtureList
|
||||
: public List<Fixture>
|
||||
{
|
||||
template <typename _Ty>
|
||||
class IteratorImpl
|
||||
: public std::iterator<std::forward_iterator_tag, _Ty>
|
||||
{
|
||||
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
|
||||
|
||||
public:
|
||||
IteratorImpl(const _Ty& elem)
|
||||
: elem_(elem)
|
||||
{
|
||||
}
|
||||
|
||||
inline typename herit::reference operator*() const
|
||||
{
|
||||
return const_cast<typename herit::reference>(elem_);
|
||||
}
|
||||
|
||||
inline typename herit::pointer operator->() const
|
||||
{
|
||||
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
||||
}
|
||||
|
||||
inline IteratorImpl& operator++()
|
||||
{
|
||||
elem_ = elem_.GetB2Fixture()->GetNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline IteratorImpl operator++(int)
|
||||
{
|
||||
IteratorImpl old = *this;
|
||||
operator++();
|
||||
return old;
|
||||
}
|
||||
|
||||
inline bool operator== (const IteratorImpl& rhs) const
|
||||
{
|
||||
return elem_ == rhs.elem_;
|
||||
}
|
||||
|
||||
inline bool operator!= (const IteratorImpl& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
_Ty elem_;
|
||||
};
|
||||
|
||||
public:
|
||||
using value_type = Fixture;
|
||||
using iterator = IteratorImpl<value_type>;
|
||||
using const_iterator = IteratorImpl<const value_type>;
|
||||
|
||||
inline FixtureList()
|
||||
{
|
||||
}
|
||||
|
||||
inline FixtureList(const value_type& first)
|
||||
: first_(first)
|
||||
{
|
||||
}
|
||||
|
||||
inline const value_type& front() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline value_type& front()
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline iterator begin()
|
||||
{
|
||||
return iterator(first_);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const
|
||||
{
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
inline const_iterator cbegin() const
|
||||
{
|
||||
return const_iterator(first_);
|
||||
}
|
||||
|
||||
inline iterator end()
|
||||
{
|
||||
return iterator(nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator end() const
|
||||
{
|
||||
return cend();
|
||||
}
|
||||
|
||||
inline const_iterator cend() const
|
||||
{
|
||||
return const_iterator(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
value_type first_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline bool Fixture::IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); }
|
||||
inline void Fixture::SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); }
|
||||
inline float Fixture::GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); }
|
||||
inline void Fixture::SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); }
|
||||
inline float Fixture::GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); }
|
||||
inline void Fixture::SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); }
|
||||
inline float Fixture::GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); }
|
||||
inline void Fixture::SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); }
|
||||
inline bool Fixture::IsValid() const { return fixture_ != nullptr; }
|
||||
inline b2Fixture* Fixture::GetB2Fixture() const { return fixture_; }
|
||||
inline void Fixture::SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; }
|
||||
inline bool Fixture::operator==(const Fixture& rhs) const { return fixture_ == rhs.fixture_; }
|
||||
inline bool Fixture::operator!=(const Fixture& rhs) const { return fixture_ != rhs.fixture_; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,14 +126,14 @@ namespace kiwano
|
|||
|
||||
void DistanceJoint::SetLength(float length)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetLength(world_->Stage2World(length));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetLength(GetWorld()->Stage2World(length));
|
||||
}
|
||||
|
||||
float DistanceJoint::GetLength() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetLength());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetLength());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -181,14 +181,14 @@ namespace kiwano
|
|||
|
||||
void FrictionJoint::SetMaxTorque(float length)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetMaxTorque(world_->Stage2World(length));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length));
|
||||
}
|
||||
|
||||
float FrictionJoint::GetMaxTorque() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetMaxTorque());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetMaxTorque());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -207,7 +207,7 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
GearJoint::GearJoint(World* world, GearJoint::Param const& param)
|
||||
GearJoint::GearJoint(World* world, GearJoint::Param param)
|
||||
: Joint()
|
||||
, raw_joint_(nullptr)
|
||||
{
|
||||
|
|
@ -260,6 +260,7 @@ namespace kiwano
|
|||
def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body());
|
||||
def.maxForce = param.max_force;
|
||||
def.maxTorque = world->Stage2World(param.max_torque);
|
||||
def.correctionFactor = param.correction_factor;
|
||||
|
||||
Init(world, &def);
|
||||
raw_joint_ = static_cast<b2MotorJoint*>(GetB2Joint());
|
||||
|
|
@ -279,14 +280,14 @@ namespace kiwano
|
|||
|
||||
void MotorJoint::SetMaxTorque(float length)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetMaxTorque(world_->Stage2World(length));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length));
|
||||
}
|
||||
|
||||
float MotorJoint::GetMaxTorque() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetMaxTorque());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetMaxTorque());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -326,32 +327,32 @@ namespace kiwano
|
|||
|
||||
float PrismaticJoint::GetJointTranslation() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetJointTranslation());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetJointTranslation());
|
||||
}
|
||||
|
||||
float PrismaticJoint::GetJointSpeed() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetJointSpeed());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetJointSpeed());
|
||||
}
|
||||
|
||||
float PrismaticJoint::GetLowerLimit() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetLowerLimit());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetLowerLimit());
|
||||
}
|
||||
|
||||
float PrismaticJoint::GetUpperLimit() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetUpperLimit());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetUpperLimit());
|
||||
}
|
||||
|
||||
void PrismaticJoint::SetLimits(float lower, float upper)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetLimits(world_->Stage2World(lower), world_->Stage2World(upper));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetLimits(GetWorld()->Stage2World(lower), GetWorld()->Stage2World(upper));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -386,14 +387,14 @@ namespace kiwano
|
|||
|
||||
Point PulleyJoint::GetGroundAnchorA() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetGroundAnchorA());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorA());
|
||||
}
|
||||
|
||||
Point PulleyJoint::GetGroundAnchorB() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetGroundAnchorB());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorB());
|
||||
}
|
||||
|
||||
float PulleyJoint::GetRatio() const
|
||||
|
|
@ -404,26 +405,26 @@ namespace kiwano
|
|||
|
||||
float PulleyJoint::GetLengthA() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetLengthA());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetLengthA());
|
||||
}
|
||||
|
||||
float PulleyJoint::GetLengthB() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetLengthB());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetLengthB());
|
||||
}
|
||||
|
||||
float PulleyJoint::GetCurrentLengthA() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetCurrentLengthA());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthA());
|
||||
}
|
||||
|
||||
float PulleyJoint::GetCurrentLengthB() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetCurrentLengthB());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthB());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -463,44 +464,44 @@ namespace kiwano
|
|||
|
||||
float RevoluteJoint::GetJointAngle() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return math::Radian2Degree(raw_joint_->GetJointAngle());
|
||||
}
|
||||
|
||||
float RevoluteJoint::GetJointSpeed() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return math::Radian2Degree(raw_joint_->GetJointSpeed());
|
||||
}
|
||||
|
||||
float RevoluteJoint::GetLowerLimit() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return math::Radian2Degree(raw_joint_->GetLowerLimit());
|
||||
}
|
||||
|
||||
float RevoluteJoint::GetUpperLimit() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return math::Radian2Degree(raw_joint_->GetUpperLimit());
|
||||
}
|
||||
|
||||
void RevoluteJoint::SetLimits(float lower, float upper)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetLimits(math::Degree2Radian(lower), math::Degree2Radian(upper));
|
||||
}
|
||||
|
||||
void RevoluteJoint::SetMaxMotorTorque(float torque)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetMaxMotorTorque(world_->Stage2World(torque));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque));
|
||||
}
|
||||
|
||||
float RevoluteJoint::GetMaxMotorTorque() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetMaxMotorTorque());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -538,14 +539,14 @@ namespace kiwano
|
|||
|
||||
void RopeJoint::SetMaxLength(float length)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetMaxLength(world_->Stage2World(length));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetMaxLength(GetWorld()->Stage2World(length));
|
||||
}
|
||||
|
||||
float RopeJoint::GetMaxLength() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetMaxLength());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetMaxLength());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -579,6 +580,7 @@ namespace kiwano
|
|||
raw_joint_ = static_cast<b2WeldJoint*>(GetB2Joint());
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// WheelJoint
|
||||
//
|
||||
|
|
@ -615,26 +617,26 @@ namespace kiwano
|
|||
|
||||
float WheelJoint::GetJointTranslation() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetJointTranslation());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetJointTranslation());
|
||||
}
|
||||
|
||||
float WheelJoint::GetJointLinearSpeed() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetJointLinearSpeed());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetJointLinearSpeed());
|
||||
}
|
||||
|
||||
void WheelJoint::SetMaxMotorTorque(float torque)
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
raw_joint_->SetMaxMotorTorque(world_->Stage2World(torque));
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque));
|
||||
}
|
||||
|
||||
float WheelJoint::GetMaxMotorTorque() const
|
||||
{
|
||||
KGE_ASSERT(raw_joint_ && world_);
|
||||
return world_->World2Stage(raw_joint_->GetMaxMotorTorque());
|
||||
KGE_ASSERT(raw_joint_ && GetWorld());
|
||||
return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -39,34 +39,51 @@ namespace kiwano
|
|||
KGE_DECLARE_SMART_PTR(WeldJoint);
|
||||
KGE_DECLARE_SMART_PTR(WheelJoint);
|
||||
|
||||
// 关节
|
||||
/**
|
||||
* \addtogroup Physics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 关节
|
||||
class KGE_API Joint
|
||||
: public virtual RefCounter
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 关节类型
|
||||
enum class Type
|
||||
{
|
||||
Unknown = 0,
|
||||
Revolute,
|
||||
Prismatic,
|
||||
Distance,
|
||||
Pulley,
|
||||
Mouse,
|
||||
Gear,
|
||||
Wheel,
|
||||
Weld,
|
||||
Friction,
|
||||
Rope,
|
||||
Motor
|
||||
Unknown = 0, ///< 未知
|
||||
Revolute, ///< 旋转关节
|
||||
Prismatic, ///< 平移关节
|
||||
Distance, ///< 固定距离关节
|
||||
Pulley, ///< 滑轮关节
|
||||
Mouse, ///< 鼠标关节
|
||||
Gear, ///< 齿轮关节
|
||||
Wheel, ///< 轮关节
|
||||
Weld, ///< 焊接关节
|
||||
Friction, ///< 摩擦关节
|
||||
Rope, ///< 绳关节
|
||||
Motor ///< 马达关节
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 关节基础参数
|
||||
struct ParamBase
|
||||
{
|
||||
Body* body_a;
|
||||
Body* body_b;
|
||||
Body* body_a; ///< 关节连接的物体A
|
||||
Body* body_b; ///< 关节连接的物体B
|
||||
|
||||
ParamBase(Body* body_a, Body* body_b) : body_a(body_a), body_b(body_b) {}
|
||||
ParamBase(BodyPtr body_a, BodyPtr body_b) : body_a(body_a.get()), body_b(body_b.get()) {}
|
||||
ParamBase(Body* body_a, Body* body_b)
|
||||
: body_a(body_a), body_b(body_b)
|
||||
{
|
||||
}
|
||||
|
||||
ParamBase(BodyPtr body_a, BodyPtr body_b)
|
||||
: body_a(body_a.get()), body_b(body_b.get())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Joint();
|
||||
|
|
@ -74,36 +91,46 @@ namespace kiwano
|
|||
Joint(World* world, b2JointDef* joint_def);
|
||||
virtual ~Joint();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 初始化关节
|
||||
void Init(World* world, b2JointDef* joint_def);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节连接的物体A
|
||||
BodyPtr GetBodyA() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节连接的物体B
|
||||
BodyPtr GetBodyB() const;
|
||||
|
||||
b2Joint* GetB2Joint() { return joint_; }
|
||||
const b2Joint* GetB2Joint() const { return joint_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取物理世界
|
||||
World* GetWorld() const;
|
||||
|
||||
b2Joint* GetB2Joint() const;
|
||||
void SetB2Joint(b2Joint* joint);
|
||||
|
||||
World* GetWorld() { return world_; }
|
||||
const World* GetWorld() const { return world_; }
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2Joint* joint_;
|
||||
World* world_;
|
||||
Type type_;
|
||||
};
|
||||
|
||||
|
||||
// 固定距离关节
|
||||
/// \~chinese
|
||||
/// @brief 固定距离关节
|
||||
class KGE_API DistanceJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 固定距离关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor_a;
|
||||
Point anchor_b;
|
||||
float frequency_hz;
|
||||
float damping_ratio;
|
||||
Point anchor_a; ///< 关节在物体A上的连接点
|
||||
Point anchor_b; ///< 关节在物体B上的连接点
|
||||
float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
|
||||
float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -136,32 +163,46 @@ namespace kiwano
|
|||
DistanceJoint(World* world, b2DistanceJointDef* def);
|
||||
DistanceJoint(World* world, Param const& param);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置关节长度
|
||||
void SetLength(float length);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节长度
|
||||
float GetLength() const;
|
||||
|
||||
// 设置弹簧阻尼器频率 [赫兹]
|
||||
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
|
||||
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
|
||||
/// \~chinese
|
||||
/// @brief 设置弹簧响应速度 [赫兹]
|
||||
void SetFrequency(float hz);
|
||||
|
||||
// 设置阻尼比
|
||||
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
|
||||
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取弹簧响应速度 [赫兹]
|
||||
float GetFrequency() const;
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 设置阻尼率
|
||||
void SetDampingRatio(float ratio);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取阻尼率
|
||||
float GetDampingRatio() const;
|
||||
|
||||
private:
|
||||
b2DistanceJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 摩擦关节
|
||||
/// \~chinese
|
||||
/// @brief 摩擦关节
|
||||
class KGE_API FrictionJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor;
|
||||
float max_force;
|
||||
float max_torque;
|
||||
Point anchor; ///< 摩擦作用点
|
||||
float max_force; ///< 最大摩擦力
|
||||
float max_torque; ///< 最大扭力
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -191,29 +232,40 @@ namespace kiwano
|
|||
FrictionJoint(World* world, b2FrictionJointDef* def);
|
||||
FrictionJoint(World* world, Param const& param);
|
||||
|
||||
// 设定最大摩擦力
|
||||
/// \~chinese
|
||||
/// @brief 设置最大摩擦力
|
||||
void SetMaxForce(float force);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大摩擦力
|
||||
float GetMaxForce() const;
|
||||
|
||||
// 设定最大转矩
|
||||
/// \~chinese
|
||||
/// @brief 设置最大转矩
|
||||
void SetMaxTorque(float torque);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大转矩
|
||||
float GetMaxTorque() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2FrictionJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 齿轮关节
|
||||
/// \~chinese
|
||||
/// @brief 齿轮关节
|
||||
class KGE_API GearJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 齿轮关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
JointPtr joint_a;
|
||||
JointPtr joint_b;
|
||||
float ratio;
|
||||
JointPtr joint_a; ///< 关节A(旋转关节/平移关节)
|
||||
JointPtr joint_b; ///< 关节B(旋转关节/平移关节)
|
||||
float ratio; ///< 齿轮传动比
|
||||
|
||||
Param(
|
||||
Joint* joint_a,
|
||||
|
|
@ -237,27 +289,34 @@ namespace kiwano
|
|||
|
||||
GearJoint();
|
||||
GearJoint(World* world, b2GearJointDef* def);
|
||||
GearJoint(World* world, Param const& param);
|
||||
GearJoint(World* world, Param param);
|
||||
|
||||
// 设定齿轮传动比
|
||||
/// \~chinese
|
||||
/// @brief 设定齿轮传动比
|
||||
void SetRatio(float ratio);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取齿轮传动比
|
||||
float GetRatio() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2GearJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 马达关节
|
||||
/// \~chinese
|
||||
/// @brief 马达关节
|
||||
class KGE_API MotorJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 马达关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
float max_force;
|
||||
float max_torque;
|
||||
float correction_factor;
|
||||
float max_force; ///< 最大摩擦力
|
||||
float max_torque; ///< 最大转矩
|
||||
float correction_factor; ///< 位置矫正因子(范围 0-1)
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -287,34 +346,45 @@ namespace kiwano
|
|||
MotorJoint(World* world, b2MotorJointDef* def);
|
||||
MotorJoint(World* world, Param const& param);
|
||||
|
||||
// 设定最大摩擦力
|
||||
/// \~chinese
|
||||
/// @brief 设置最大摩擦力
|
||||
void SetMaxForce(float force);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大摩擦力
|
||||
float GetMaxForce() const;
|
||||
|
||||
// 设定最大转矩
|
||||
/// \~chinese
|
||||
/// @brief 设置最大转矩
|
||||
void SetMaxTorque(float torque);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大转矩
|
||||
float GetMaxTorque() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2MotorJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 平移关节
|
||||
/// \~chinese
|
||||
/// @brief 平移关节
|
||||
class KGE_API PrismaticJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 平移关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor;
|
||||
Vec2 axis;
|
||||
bool enable_limit;
|
||||
float lower_translation;
|
||||
float upper_translation;
|
||||
bool enable_motor;
|
||||
float max_motor_force;
|
||||
float motor_speed;
|
||||
Point anchor; ///< 关节位置
|
||||
Vec2 axis; ///< 物体A滑动的方向
|
||||
bool enable_limit; ///< 是否启用限制
|
||||
float lower_translation; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果
|
||||
float upper_translation; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果
|
||||
bool enable_motor; ///< 是否启用马达
|
||||
float max_motor_force; ///< 最大马达力 [N]
|
||||
float motor_speed; ///< 马达转速 [degree/s]
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -359,45 +429,82 @@ namespace kiwano
|
|||
PrismaticJoint(World* world, b2PrismaticJointDef* def);
|
||||
PrismaticJoint(World* world, Param const& param);
|
||||
|
||||
float GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
|
||||
/// \~chinese
|
||||
/// @brief 获取参考角
|
||||
float GetReferenceAngle() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节转换
|
||||
float GetJointTranslation() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节速度
|
||||
float GetJointSpeed() const;
|
||||
|
||||
bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
|
||||
void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 是否启用关节限制
|
||||
bool IsLimitEnabled() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置是否启用关节限制
|
||||
void EnableLimit(bool flag);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取平移最小限制
|
||||
float GetLowerLimit() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取平移最大限制
|
||||
float GetUpperLimit() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置关节限制
|
||||
void SetLimits(float lower, float upper);
|
||||
|
||||
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
|
||||
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 是否启用马达
|
||||
bool IsMotorEnabled() const;
|
||||
|
||||
// 设置马达转速 [degree/s]
|
||||
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
|
||||
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
|
||||
/// \~chinese
|
||||
/// @brief 设置是否启用马达
|
||||
void EnableMotor(bool flag);
|
||||
|
||||
// 设定最大马达力 [N]
|
||||
void SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); }
|
||||
float GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); }
|
||||
/// \~chinese
|
||||
/// @brief 设置马达转速 [degree/s]
|
||||
void SetMotorSpeed(float speed);
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 获取马达转速 [degree/s]
|
||||
float GetMotorSpeed() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置最大马达力 [N]
|
||||
void SetMaxMotorForce(float force);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大马达力 [N]
|
||||
float GetMaxMotorForce() const;
|
||||
|
||||
private:
|
||||
b2PrismaticJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 滑轮关节
|
||||
/// \~chinese
|
||||
/// @brief 滑轮关节
|
||||
class KGE_API PulleyJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 滑轮关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor_a;
|
||||
Point anchor_b;
|
||||
Point ground_anchor_a;
|
||||
Point ground_anchor_b;
|
||||
float ratio;
|
||||
Point anchor_a; ///< 关节在物体A上的作用点
|
||||
Point anchor_b; ///< 关节在物体B上的作用点
|
||||
Point ground_anchor_a; ///< 物体A对应的滑轮的位置
|
||||
Point ground_anchor_b; ///< 物体B对应的滑轮的位置
|
||||
float ratio; ///< 滑轮比,关节传动时,滑轮上升和下降的两头的位移比例
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -433,36 +540,56 @@ namespace kiwano
|
|||
PulleyJoint(World* world, b2PulleyJointDef* def);
|
||||
PulleyJoint(World* world, Param const& param);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物体A对应的滑轮的位置
|
||||
Point GetGroundAnchorA() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物体B对应的滑轮的位置
|
||||
Point GetGroundAnchorB() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取滑轮传动比
|
||||
float GetRatio() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体A与滑轮的距离
|
||||
float GetLengthA() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体B与滑轮的距离
|
||||
float GetLengthB() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体A与滑轮的当前距离
|
||||
float GetCurrentLengthA() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取物体B与滑轮的当前距离
|
||||
float GetCurrentLengthB() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2PulleyJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 旋转关节
|
||||
/// \~chinese
|
||||
/// @brief 旋转关节
|
||||
class KGE_API RevoluteJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 旋转关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor;
|
||||
bool enable_limit;
|
||||
float lower_angle;
|
||||
float upper_angle;
|
||||
bool enable_motor;
|
||||
float max_motor_torque;
|
||||
float motor_speed;
|
||||
Point anchor; ///< 关节位置
|
||||
bool enable_limit; ///< 是否启用限制
|
||||
float lower_angle; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果
|
||||
float upper_angle; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果
|
||||
bool enable_motor; ///< 是否启用马达
|
||||
float max_motor_torque; ///< 最大马达力 [N]
|
||||
float motor_speed; ///< 马达转速 [degree/s]
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -504,43 +631,80 @@ namespace kiwano
|
|||
RevoluteJoint(World* world, b2RevoluteJointDef* def);
|
||||
RevoluteJoint(World* world, Param const& param);
|
||||
|
||||
float GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
|
||||
/// \~chinese
|
||||
/// @brief 获取参考角
|
||||
float GetReferenceAngle() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节角度
|
||||
float GetJointAngle() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节速度
|
||||
float GetJointSpeed() const;
|
||||
|
||||
bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
|
||||
void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 是否启用关节限制
|
||||
bool IsLimitEnabled() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置是否启用关节限制
|
||||
void EnableLimit(bool flag);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取平移最小限制
|
||||
float GetLowerLimit() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取平移最大限制
|
||||
float GetUpperLimit() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置关节限制
|
||||
void SetLimits(float lower, float upper);
|
||||
|
||||
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
|
||||
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 是否启用马达
|
||||
bool IsMotorEnabled() const;
|
||||
|
||||
// 设置马达转速 [degree/s]
|
||||
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
|
||||
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
|
||||
/// \~chinese
|
||||
/// @brief 设置是否启用马达
|
||||
void EnableMotor(bool flag);
|
||||
|
||||
// 设定最大马达转矩 [N/m]
|
||||
/// \~chinese
|
||||
/// @brief 设置马达转速 [degree/s]
|
||||
void SetMotorSpeed(float speed);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取马达转速 [degree/s]
|
||||
float GetMotorSpeed() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置最大马达转矩 [N/m]
|
||||
void SetMaxMotorTorque(float torque);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大马达转矩 [N/m]
|
||||
float GetMaxMotorTorque() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2RevoluteJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 绳关节
|
||||
/// \~chinese
|
||||
/// @brief 绳关节
|
||||
class KGE_API RopeJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 绳关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point local_anchor_a;
|
||||
Point local_anchor_b;
|
||||
float max_length;
|
||||
Point local_anchor_a; ///< 关节在物体A上的连接点
|
||||
Point local_anchor_b; ///< 关节在物体B上的连接点
|
||||
float max_length; ///< 绳索最大长度
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -570,24 +734,32 @@ namespace kiwano
|
|||
RopeJoint(World* world, b2RopeJointDef* def);
|
||||
RopeJoint(World* world, Param const& param);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置关节最大长度
|
||||
void SetMaxLength(float length);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节最大长度
|
||||
float GetMaxLength() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2RopeJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 焊接关节
|
||||
/// \~chinese
|
||||
/// @brief 焊接关节
|
||||
class KGE_API WeldJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 焊接关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor;
|
||||
float frequency_hz;
|
||||
float damping_ratio;
|
||||
Point anchor; ///< 焊接位置
|
||||
float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
|
||||
float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -617,33 +789,48 @@ namespace kiwano
|
|||
WeldJoint(World* world, b2WeldJointDef* def);
|
||||
WeldJoint(World* world, Param const& param);
|
||||
|
||||
// 设置弹簧阻尼器频率 [赫兹]
|
||||
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
|
||||
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取物体B相对于物体A的角度
|
||||
float GetReferenceAngle() const;
|
||||
|
||||
// 设置阻尼比
|
||||
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
|
||||
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
|
||||
/// \~chinese
|
||||
/// @brief 设置弹簧响应速度 [赫兹]
|
||||
void SetFrequency(float hz);
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 获取弹簧响应速度 [赫兹]
|
||||
float GetFrequency() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置阻尼率
|
||||
void SetDampingRatio(float ratio);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取阻尼率
|
||||
float GetDampingRatio() const;
|
||||
|
||||
private:
|
||||
b2WeldJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 轮关节
|
||||
/// \~chinese
|
||||
/// @brief 轮关节
|
||||
class KGE_API WheelJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 轮关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point anchor;
|
||||
Vec2 axis;
|
||||
bool enable_motor;
|
||||
float max_motor_torque;
|
||||
float motor_speed;
|
||||
float frequency_hz;
|
||||
float damping_ratio;
|
||||
Point anchor; ///< 轮关节位置
|
||||
Vec2 axis; ///< 物体A滑动方向
|
||||
bool enable_motor; ///< 是否启用马达
|
||||
float max_motor_torque; ///< 最大马达力 [N]
|
||||
float motor_speed; ///< 马达转速 [degree/s]
|
||||
float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
|
||||
float damping_ratio; ///< 弹簧阻尼率,值越大关节运动阻尼越大
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -685,45 +872,82 @@ namespace kiwano
|
|||
WheelJoint(World* world, b2WheelJointDef* def);
|
||||
WheelJoint(World* world, Param const& param);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节当前的平移距离
|
||||
float GetJointTranslation() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取关节当前的线性速度
|
||||
float GetJointLinearSpeed() const;
|
||||
float GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); }
|
||||
float GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); }
|
||||
|
||||
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
|
||||
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
|
||||
/// \~chinese
|
||||
/// @brief 获取关节当前的角度
|
||||
float GetJointAngle() const;
|
||||
|
||||
// 设置马达转速 [degree/s]
|
||||
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
|
||||
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
|
||||
/// \~chinese
|
||||
/// @brief 获取关节当前的旋转速度
|
||||
float GetJointAngularSpeed() const;
|
||||
|
||||
// 设定最大马达转矩 [N/m]
|
||||
/// \~chinese
|
||||
/// @brief 是否启用马达
|
||||
bool IsMotorEnabled() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置是否启用马达
|
||||
void EnableMotor(bool flag);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置马达转速 [degree/s]
|
||||
void SetMotorSpeed(float speed);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取马达转速 [degree/s]
|
||||
float GetMotorSpeed() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置最大马达转矩 [N/m]
|
||||
void SetMaxMotorTorque(float torque);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大马达转矩 [N/m]
|
||||
float GetMaxMotorTorque() const;
|
||||
|
||||
void SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); }
|
||||
float GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); }
|
||||
/// \~chinese
|
||||
/// @brief 设置弹簧响应速度
|
||||
void SetSpringFrequencyHz(float hz);
|
||||
|
||||
void SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); }
|
||||
float GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取弹簧响应速度
|
||||
float GetSpringFrequencyHz() const;
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 设置弹簧阻尼率
|
||||
void SetSpringDampingRatio(float ratio);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取弹簧阻尼率
|
||||
float GetSpringDampingRatio() const;
|
||||
|
||||
private:
|
||||
b2WheelJoint* raw_joint_;
|
||||
};
|
||||
|
||||
|
||||
// 鼠标关节
|
||||
// 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
|
||||
/// \~chinese
|
||||
/// @brief 鼠标关节
|
||||
/// @details 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
|
||||
class KGE_API MouseJoint
|
||||
: public Joint
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 鼠标关节参数
|
||||
struct Param : public Joint::ParamBase
|
||||
{
|
||||
Point target;
|
||||
float max_force;
|
||||
float frequency_hz;
|
||||
float damping_ratio;
|
||||
Point target; ///< 关节作用目标位置
|
||||
float max_force; ///< 作用在物体A上的最大力
|
||||
float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固
|
||||
float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大
|
||||
|
||||
Param(
|
||||
Body* body_a,
|
||||
|
|
@ -740,14 +964,7 @@ namespace kiwano
|
|||
, damping_ratio(damping_ratio)
|
||||
{}
|
||||
|
||||
Param(
|
||||
BodyPtr body_a,
|
||||
BodyPtr body_b,
|
||||
Point const& target,
|
||||
float max_force,
|
||||
float frequency_hz = 5.0f,
|
||||
float damping_ratio = 0.7f
|
||||
)
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f, float damping_ratio = 0.7f)
|
||||
: Param(body_a.get(), body_b.get(), target, max_force, frequency_hz, damping_ratio)
|
||||
{}
|
||||
};
|
||||
|
|
@ -756,20 +973,83 @@ namespace kiwano
|
|||
MouseJoint(World* world, b2MouseJointDef* def);
|
||||
MouseJoint(World* world, Param const& param);
|
||||
|
||||
// 设定最大摩擦力 [N]
|
||||
/// \~chinese
|
||||
/// @brief 设定最大摩擦力 [N]
|
||||
void SetMaxForce(float force);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取最大摩擦力 [N]
|
||||
float GetMaxForce() const;
|
||||
|
||||
// 设置响应速度 [hz]
|
||||
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
|
||||
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
|
||||
/// \~chinese
|
||||
/// @brief 设置响应速度 [hz]
|
||||
void SetFrequency(float hz);
|
||||
|
||||
// 设置阻尼比
|
||||
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
|
||||
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取响应速度 [hz]
|
||||
float GetFrequency() const;
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 设置阻尼率
|
||||
void SetDampingRatio(float ratio);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取阻尼率
|
||||
float GetDampingRatio() const;
|
||||
|
||||
private:
|
||||
b2MouseJoint* raw_joint_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
inline b2Joint* Joint::GetB2Joint() const { return joint_; }
|
||||
inline World* Joint::GetWorld() const { return world_; }
|
||||
|
||||
inline void DistanceJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
|
||||
inline float DistanceJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
|
||||
inline void DistanceJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
|
||||
inline float DistanceJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
|
||||
|
||||
inline float PrismaticJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
|
||||
inline bool PrismaticJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
|
||||
inline void PrismaticJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
|
||||
inline bool PrismaticJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
|
||||
inline void PrismaticJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
|
||||
inline void PrismaticJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
|
||||
inline float PrismaticJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
|
||||
inline void PrismaticJoint::SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); }
|
||||
inline float PrismaticJoint::GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); }
|
||||
|
||||
inline float RevoluteJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
|
||||
inline bool RevoluteJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
|
||||
inline void RevoluteJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
|
||||
inline bool RevoluteJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
|
||||
inline void RevoluteJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
|
||||
inline void RevoluteJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
|
||||
inline float RevoluteJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
|
||||
|
||||
inline float WeldJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
|
||||
inline void WeldJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
|
||||
inline float WeldJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
|
||||
inline void WeldJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
|
||||
inline float WeldJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
|
||||
|
||||
inline float WheelJoint::GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); }
|
||||
inline float WheelJoint::GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); }
|
||||
inline bool WheelJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
|
||||
inline void WheelJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
|
||||
inline void WheelJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
|
||||
inline float WheelJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
|
||||
inline void WheelJoint::SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); }
|
||||
inline float WheelJoint::GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); }
|
||||
inline void WheelJoint::SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); }
|
||||
inline float WheelJoint::GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); }
|
||||
|
||||
inline void MouseJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
|
||||
inline float MouseJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
|
||||
inline void MouseJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
|
||||
inline float MouseJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,12 +35,7 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
b2Shape* Shape::GetB2Shape()
|
||||
{
|
||||
return shape_;
|
||||
}
|
||||
|
||||
const b2Shape* Shape::GetB2Shape() const
|
||||
b2Shape* Shape::GetB2Shape() const
|
||||
{
|
||||
return shape_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,25 +26,35 @@ namespace kiwano
|
|||
namespace physics
|
||||
{
|
||||
class World;
|
||||
class Fixture;
|
||||
|
||||
// 形状基类
|
||||
/**
|
||||
* \addtogroup Physics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 形状基类
|
||||
class KGE_API Shape
|
||||
{
|
||||
friend class Fixture;
|
||||
|
||||
public:
|
||||
Shape();
|
||||
Shape(b2Shape* shape);
|
||||
|
||||
b2Shape* GetB2Shape();
|
||||
const b2Shape* GetB2Shape() const;
|
||||
b2Shape* GetB2Shape() const;
|
||||
void SetB2Shape(b2Shape* shape);
|
||||
|
||||
private:
|
||||
virtual void FitWorld(World* world) {}
|
||||
|
||||
protected:
|
||||
private:
|
||||
b2Shape* shape_;
|
||||
};
|
||||
|
||||
// 圆形形状
|
||||
/// \~chinese
|
||||
/// @brief 圆形形状
|
||||
class KGE_API CircleShape
|
||||
: public Shape
|
||||
{
|
||||
|
|
@ -55,15 +65,17 @@ namespace kiwano
|
|||
|
||||
void Set(float radius, Point const& offset = Point());
|
||||
|
||||
private:
|
||||
void FitWorld(World* world) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
float radius_;
|
||||
Point offset_;
|
||||
b2CircleShape circle_;
|
||||
};
|
||||
|
||||
// 盒子形状
|
||||
/// \~chinese
|
||||
/// @brief 盒子形状
|
||||
class KGE_API BoxShape
|
||||
: public Shape
|
||||
{
|
||||
|
|
@ -74,16 +86,18 @@ namespace kiwano
|
|||
|
||||
void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
|
||||
|
||||
private:
|
||||
void FitWorld(World* world) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
float rotation_;
|
||||
Vec2 box_size_;
|
||||
Point offset_;
|
||||
b2PolygonShape polygon_;
|
||||
};
|
||||
|
||||
// 多边形形状
|
||||
/// \~chinese
|
||||
/// @brief 多边形形状
|
||||
class KGE_API PolygonShape
|
||||
: public Shape
|
||||
{
|
||||
|
|
@ -94,14 +108,16 @@ namespace kiwano
|
|||
|
||||
void Set(Vector<Point> const& vertexs);
|
||||
|
||||
private:
|
||||
void FitWorld(World* world) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
Vector<Point> vertexs_;
|
||||
b2PolygonShape polygon_;
|
||||
};
|
||||
|
||||
// 线段形状, 用于表示一条边
|
||||
/// \~chinese
|
||||
/// @brief 线段形状, 用于表示一条边
|
||||
class KGE_API EdgeShape
|
||||
: public Shape
|
||||
{
|
||||
|
|
@ -112,14 +128,16 @@ namespace kiwano
|
|||
|
||||
void Set(Point const& p1, Point const& p2);
|
||||
|
||||
private:
|
||||
void FitWorld(World* world) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
Point p_[2];
|
||||
b2EdgeShape edge_;
|
||||
};
|
||||
|
||||
// 链式形状
|
||||
/// \~chinese
|
||||
/// @brief 链式形状
|
||||
class KGE_API ChainShape
|
||||
: public Shape
|
||||
{
|
||||
|
|
@ -130,12 +148,15 @@ namespace kiwano
|
|||
|
||||
void Set(Vector<Point> const& vertexs, bool loop = false);
|
||||
|
||||
private:
|
||||
void FitWorld(World* world) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
bool loop_;
|
||||
Vector<Point> vertexs_;
|
||||
b2ChainShape chain_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace kiwano
|
|||
{
|
||||
namespace
|
||||
{
|
||||
const float DefaultGlobalScale = 100.f; // 100 pixels per meters
|
||||
const float default_global_scale = 100.f; // 100 pixels per meters
|
||||
}
|
||||
|
||||
class World::DestructionListener : public b2DestructionListener
|
||||
|
|
@ -85,7 +85,7 @@ namespace kiwano
|
|||
: world_(b2Vec2(0, 10.0f))
|
||||
, vel_iter_(6)
|
||||
, pos_iter_(2)
|
||||
, global_scale_(DefaultGlobalScale)
|
||||
, global_scale_(default_global_scale)
|
||||
, destruction_listener_(nullptr)
|
||||
, contact_listener_(nullptr)
|
||||
, removing_joint_(false)
|
||||
|
|
@ -225,36 +225,25 @@ namespace kiwano
|
|||
world_.SetGravity(b2Vec2(gravity.x, gravity.y));
|
||||
}
|
||||
|
||||
ContactList World::GetContactList()
|
||||
{
|
||||
return ContactList(Contact(world_.GetContactList()));
|
||||
}
|
||||
|
||||
void World::Update(Duration dt)
|
||||
{
|
||||
{
|
||||
b2Body* b2body = world_.GetBodyList();
|
||||
while (b2body)
|
||||
{
|
||||
Body* body = static_cast<Body*>(b2body->GetUserData());
|
||||
if (body && body->GetType() != Body::Type::Static)
|
||||
{
|
||||
body->UpdateFromActor();
|
||||
}
|
||||
|
||||
b2body = b2body->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
|
||||
|
||||
b2Body* b2body = world_.GetBodyList();
|
||||
while (b2body)
|
||||
{
|
||||
b2Body* b2body = world_.GetBodyList();
|
||||
while (b2body)
|
||||
Body* body = static_cast<Body*>(b2body->GetUserData());
|
||||
if (body && body->GetType() != Body::Type::Static)
|
||||
{
|
||||
Body* body = static_cast<Body*>(b2body->GetUserData());
|
||||
if (body && body->GetType() != Body::Type::Static)
|
||||
{
|
||||
body->UpdateActor();
|
||||
}
|
||||
|
||||
b2body = b2body->GetNext();
|
||||
body->UpdateActor();
|
||||
}
|
||||
|
||||
b2body = b2body->GetNext();
|
||||
}
|
||||
|
||||
Stage::Update(dt);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,22 @@ namespace kiwano
|
|||
{
|
||||
namespace physics
|
||||
{
|
||||
// 物理世界
|
||||
KGE_DECLARE_SMART_PTR(World);
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* \defgroup Physics 物理引擎
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup Physics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 物理世界
|
||||
*/
|
||||
class KGE_API World
|
||||
: public Stage
|
||||
{
|
||||
|
|
@ -38,54 +53,86 @@ namespace kiwano
|
|||
|
||||
virtual ~World();
|
||||
|
||||
// 获取重力
|
||||
/// \~chinese
|
||||
/// @brief 获取重力 [N]
|
||||
Vec2 GetGravity() const;
|
||||
|
||||
// 设置重力
|
||||
/// \~chinese
|
||||
/// @brief 设置重力 [N]
|
||||
void SetGravity(Vec2 gravity);
|
||||
|
||||
// 获取全局缩放比例
|
||||
inline float GetGlobalScale() const { return global_scale_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取物理接触列表
|
||||
ContactList GetContactList();
|
||||
|
||||
// 设置全局缩放比例
|
||||
inline void SetGlobalScale(float scale) { global_scale_ = scale; }
|
||||
/// \~chinese
|
||||
/// @brief 获取全局缩放比例
|
||||
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100
|
||||
float GetGlobalScale() const;
|
||||
|
||||
// 游戏世界单位转换为物理世界单位
|
||||
inline float World2Stage(float value) const { return value * GetGlobalScale(); }
|
||||
inline Point World2Stage(const b2Vec2& pos) const { return Point(World2Stage(pos.x), World2Stage(pos.y)); }
|
||||
/// \~chinese
|
||||
/// @brief 设置全局缩放比例
|
||||
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100
|
||||
void SetGlobalScale(float scale);
|
||||
|
||||
// 物理世界单位转换为游戏世界单位
|
||||
inline float Stage2World(float value) const { return value / GetGlobalScale(); }
|
||||
inline b2Vec2 Stage2World(const Point& pos) const { return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); }
|
||||
/// \~chinese
|
||||
/// @brief 游戏世界单位转换为物理世界单位
|
||||
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
|
||||
float World2Stage(float value) const;
|
||||
|
||||
// 设置速度迭代次数, 默认为 6
|
||||
inline void SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; }
|
||||
/// \~chinese
|
||||
/// @brief 游戏世界单位转换为物理世界单位
|
||||
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
|
||||
Vec2 World2Stage(const b2Vec2& pos) const;
|
||||
|
||||
// 设置位置迭代次数, 默认为 2
|
||||
inline void SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; }
|
||||
/// \~chinese
|
||||
/// @brief 物理世界单位转换为游戏世界单位
|
||||
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
|
||||
float Stage2World(float value) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 物理世界单位转换为游戏世界单位
|
||||
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
|
||||
b2Vec2 Stage2World(const Vec2& pos) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置速度迭代次数, 默认为 6
|
||||
void SetVelocityIterations(int vel_iter);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置位置迭代次数, 默认为 2
|
||||
void SetPositionIterations(int pos_iter);
|
||||
|
||||
b2World* GetB2World();
|
||||
|
||||
const b2World* GetB2World() const;
|
||||
|
||||
private:
|
||||
// 移除物体
|
||||
/// \~chinese
|
||||
/// @brief 移除物体
|
||||
void RemoveBody(Body* body);
|
||||
|
||||
// 移除所有物体
|
||||
/// \~chinese
|
||||
/// @brief 移除所有物体
|
||||
void RemoveAllBodies();
|
||||
|
||||
// 添加关节
|
||||
/// \~chinese
|
||||
/// @brief 添加关节
|
||||
void AddJoint(Joint* joint);
|
||||
|
||||
// 移除关节
|
||||
/// \~chinese
|
||||
/// @brief 移除关节
|
||||
void RemoveJoint(Joint* joint);
|
||||
|
||||
// 移除所有关节
|
||||
/// \~chinese
|
||||
/// @brief 移除所有关节
|
||||
void RemoveAllJoints();
|
||||
|
||||
// 关节被移除
|
||||
/// \~chinese
|
||||
/// @brief 关节被移除
|
||||
void JointRemoved(b2Joint* joint);
|
||||
|
||||
protected:
|
||||
void Update(Duration dt) override;
|
||||
|
||||
private:
|
||||
|
|
@ -106,6 +153,47 @@ namespace kiwano
|
|||
Vector<Joint*> joints_;
|
||||
};
|
||||
|
||||
KGE_DECLARE_SMART_PTR(World);
|
||||
|
||||
/** @} */
|
||||
|
||||
inline float World::GetGlobalScale() const
|
||||
{
|
||||
return global_scale_;
|
||||
}
|
||||
|
||||
inline void World::SetGlobalScale(float scale)
|
||||
{
|
||||
global_scale_ = scale;
|
||||
}
|
||||
|
||||
inline float World::World2Stage(float value) const
|
||||
{
|
||||
return value * GetGlobalScale();
|
||||
}
|
||||
|
||||
inline Vec2 World::World2Stage(const b2Vec2& pos) const
|
||||
{
|
||||
return Point(World2Stage(pos.x), World2Stage(pos.y));
|
||||
}
|
||||
|
||||
inline float World::Stage2World(float value) const
|
||||
{
|
||||
return value / GetGlobalScale();
|
||||
}
|
||||
|
||||
inline b2Vec2 World::Stage2World(const Vec2& pos) const
|
||||
{
|
||||
return b2Vec2(Stage2World(pos.x), Stage2World(pos.y));
|
||||
}
|
||||
|
||||
inline void World::SetVelocityIterations(int vel_iter)
|
||||
{
|
||||
vel_iter_ = vel_iter;
|
||||
}
|
||||
|
||||
inline void World::SetPositionIterations(int pos_iter)
|
||||
{
|
||||
pos_iter_ = pos_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace kiwano
|
|||
{
|
||||
namespace physics
|
||||
{
|
||||
inline b2Vec2 Stage2World(const Point& pos) { return b2Vec2(pos.x, pos.y); }
|
||||
inline Point World2Stage(const b2Vec2& pos) { return Point(pos.x, pos.y); }
|
||||
inline b2Vec2 Stage2World(const Vec2& pos) { return b2Vec2(pos.x, pos.y); }
|
||||
inline Vec2 World2Stage(const b2Vec2& pos) { return Vec2(pos.x, pos.y); }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,11 @@ namespace kiwano
|
|||
|
||||
if (children_.empty())
|
||||
{
|
||||
OnRender(rt);
|
||||
if (CheckVisibilty(rt))
|
||||
{
|
||||
PrepareToRender(rt);
|
||||
OnRender(rt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -108,7 +112,11 @@ namespace kiwano
|
|||
child = child->next_item().get();
|
||||
}
|
||||
|
||||
OnRender(rt);
|
||||
if (CheckVisibilty(rt))
|
||||
{
|
||||
PrepareToRender(rt);
|
||||
OnRender(rt);
|
||||
}
|
||||
|
||||
while (child)
|
||||
{
|
||||
|
|
@ -118,10 +126,10 @@ namespace kiwano
|
|||
}
|
||||
}
|
||||
|
||||
void Actor::PrepareRender(RenderTarget* rt)
|
||||
void Actor::PrepareToRender(RenderTarget* rt)
|
||||
{
|
||||
rt->SetTransform(transform_matrix_);
|
||||
rt->SetOpacity(displayed_opacity_);
|
||||
rt->SetBrushOpacity(GetDisplayedOpacity());
|
||||
}
|
||||
|
||||
void Actor::RenderBorder(RenderTarget* rt)
|
||||
|
|
@ -132,10 +140,10 @@ namespace kiwano
|
|||
|
||||
rt->SetTransform(transform_matrix_);
|
||||
|
||||
rt->SetDefaultBrushColor(Color(Color::Red, .4f));
|
||||
rt->SetCurrentBrush(GetStage()->GetBorderFillBrush());
|
||||
rt->FillRectangle(bounds);
|
||||
|
||||
rt->SetDefaultBrushColor(Color(Color::Red, .8f));
|
||||
rt->SetCurrentBrush(GetStage()->GetBorderStrokeBrush());
|
||||
rt->DrawRectangle(bounds, 2.f);
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +158,15 @@ namespace kiwano
|
|||
if (dirty_visibility_)
|
||||
{
|
||||
dirty_visibility_ = false;
|
||||
visible_in_rt_ = rt->CheckVisibility(GetBounds(), GetTransformMatrix());
|
||||
|
||||
if (size_.IsOrigin())
|
||||
{
|
||||
visible_in_rt_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
visible_in_rt_ = rt->CheckVisibility(GetBounds(), GetTransformMatrix());
|
||||
}
|
||||
}
|
||||
return visible_in_rt_;
|
||||
}
|
||||
|
|
@ -169,21 +185,21 @@ namespace kiwano
|
|||
|
||||
if (responsible_)
|
||||
{
|
||||
if (evt.type == event::MouseMove)
|
||||
if (evt.IsType<MouseMoveEvent>())
|
||||
{
|
||||
auto mouse_evt = evt.SafeCast<MouseMoveEvent>();
|
||||
if (!mouse_evt->target && ContainsPoint(mouse_evt->pos))
|
||||
auto& mouse_evt = evt.SafeCast<MouseMoveEvent>();
|
||||
if (!mouse_evt.target && ContainsPoint(mouse_evt.pos))
|
||||
{
|
||||
mouse_evt->target = this;
|
||||
mouse_evt.target = this;
|
||||
|
||||
if (!hover_)
|
||||
{
|
||||
hover_ = true;
|
||||
|
||||
MouseHoverEvent hover;
|
||||
hover.pos = mouse_evt->pos;
|
||||
hover.left_btn_down = mouse_evt->left_btn_down;
|
||||
hover.right_btn_down = mouse_evt->right_btn_down;
|
||||
hover.pos = mouse_evt.pos;
|
||||
hover.left_btn_down = mouse_evt.left_btn_down;
|
||||
hover.right_btn_down = mouse_evt.right_btn_down;
|
||||
hover.target = this;
|
||||
EventDispatcher::Dispatch(hover);
|
||||
}
|
||||
|
|
@ -194,33 +210,33 @@ namespace kiwano
|
|||
pressed_ = false;
|
||||
|
||||
MouseOutEvent out;
|
||||
out.pos = mouse_evt->pos;
|
||||
out.left_btn_down = mouse_evt->left_btn_down;
|
||||
out.right_btn_down = mouse_evt->right_btn_down;
|
||||
out.pos = mouse_evt.pos;
|
||||
out.left_btn_down = mouse_evt.left_btn_down;
|
||||
out.right_btn_down = mouse_evt.right_btn_down;
|
||||
out.target = this;
|
||||
EventDispatcher::Dispatch(out);
|
||||
}
|
||||
}
|
||||
|
||||
if (evt.type == event::MouseDown && hover_)
|
||||
if (evt.IsType<MouseDownEvent>() && hover_)
|
||||
{
|
||||
pressed_ = true;
|
||||
evt.SafeCast<MouseDownEvent>()->target = this;
|
||||
evt.SafeCast<MouseDownEvent>().target = this;
|
||||
}
|
||||
|
||||
if (evt.type == event::MouseUp && pressed_)
|
||||
if (evt.IsType<MouseUpEvent>() && pressed_)
|
||||
{
|
||||
pressed_ = false;
|
||||
|
||||
auto mouse_up_evt = evt.SafeCast<MouseUpEvent>();
|
||||
mouse_up_evt->target = this;
|
||||
mouse_up_evt.target = this;
|
||||
|
||||
MouseClickEvent click;
|
||||
click.pos = mouse_up_evt->pos;
|
||||
click.left_btn_down = mouse_up_evt->left_btn_down;
|
||||
click.right_btn_down = mouse_up_evt->right_btn_down;
|
||||
click.pos = mouse_up_evt.pos;
|
||||
click.left_btn_down = mouse_up_evt.left_btn_down;
|
||||
click.right_btn_down = mouse_up_evt.right_btn_down;
|
||||
click.target = this;
|
||||
click.button = mouse_up_evt->button;
|
||||
click.button = mouse_up_evt.button;
|
||||
EventDispatcher::Dispatch(click);
|
||||
}
|
||||
}
|
||||
|
|
@ -272,7 +288,7 @@ namespace kiwano
|
|||
}
|
||||
|
||||
// update children's transform
|
||||
for (Actor* child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (auto child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
child->dirty_transform_ = true;
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +497,7 @@ namespace kiwano
|
|||
{
|
||||
if (parent == child)
|
||||
{
|
||||
KGE_ERROR_LOG(L"A actor cannot be its own parent");
|
||||
KGE_ERROR(L"A actor cannot be its own parent");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -527,11 +543,11 @@ namespace kiwano
|
|||
Vector<ActorPtr> children;
|
||||
size_t hash_code = std::hash<String>{}(name);
|
||||
|
||||
for (Actor* child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (auto child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
{
|
||||
if (child->hash_name_ == hash_code && child->IsName(name))
|
||||
{
|
||||
children.push_back(child);
|
||||
children.push_back(const_cast<Actor*>(child));
|
||||
}
|
||||
}
|
||||
return children;
|
||||
|
|
@ -541,11 +557,11 @@ namespace kiwano
|
|||
{
|
||||
size_t hash_code = std::hash<String>{}(name);
|
||||
|
||||
for (Actor* child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (auto child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
{
|
||||
if (child->hash_name_ == hash_code && child->IsName(name))
|
||||
{
|
||||
return child;
|
||||
return const_cast<Actor*>(child);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/2d/include-forwards.h>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/time.h>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/math/math.h>
|
||||
#include <kiwano/2d/Transform.h>
|
||||
#include <kiwano/2d/action/ActionManager.h>
|
||||
#include <kiwano/core/TimerManager.h>
|
||||
|
|
@ -27,10 +30,27 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
class Stage;
|
||||
class Director;
|
||||
class RenderTarget;
|
||||
|
||||
// 角色
|
||||
KGE_DECLARE_SMART_PTR(Actor);
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* \defgroup Actors 基础角色
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup Actors
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 角色
|
||||
* @details 角色是舞台上最基本的元素,是完成渲染、更新、事件分发等功能的最小单位,也是动画、定时器、事件监听等功能的载体
|
||||
*/
|
||||
class KGE_API Actor
|
||||
: public ObjectBase
|
||||
, public TimerManager
|
||||
|
|
@ -43,353 +63,376 @@ namespace kiwano
|
|||
friend IntrusiveList<ActorPtr>;
|
||||
|
||||
public:
|
||||
using Children = IntrusiveList<ActorPtr>;
|
||||
using UpdateCallback = Function<void(Duration)>;
|
||||
/// \~chinese
|
||||
/// @brief 子成员列表
|
||||
using Children = IntrusiveList<ActorPtr>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 角色更新回调函数
|
||||
using UpdateCallback = Function<void(Duration)>;
|
||||
|
||||
Actor();
|
||||
|
||||
// 更新角色
|
||||
/// \~chinese
|
||||
/// @brief 更新角色
|
||||
/// @details 每帧画面刷新前调用该函数,重载该函数以实现角色的更新处理
|
||||
/// @param dt 距上一次更新的时间间隔
|
||||
virtual void OnUpdate(Duration dt);
|
||||
|
||||
// 渲染角色
|
||||
/// \~chinese
|
||||
/// @brief 渲染角色
|
||||
/// @details 每帧画面刷新时调用该函数,默认不进行渲染,重载该函数以实现具体渲染过程
|
||||
/// @param rt 渲染目标
|
||||
virtual void OnRender(RenderTarget* rt);
|
||||
|
||||
// 获取显示状态
|
||||
/// \~chinese
|
||||
/// @brief 获取显示状态
|
||||
bool IsVisible() const;
|
||||
|
||||
// 获取响应状态
|
||||
/// \~chinese
|
||||
/// @brief 获取响应状态
|
||||
bool IsResponsible() const;
|
||||
|
||||
// 是否启用级联透明度
|
||||
/// \~chinese
|
||||
/// @brief 是否启用级联透明度
|
||||
bool IsCascadeOpacityEnabled() const;
|
||||
|
||||
// 获取名称的 Hash 值
|
||||
/// \~chinese
|
||||
/// @brief 获取名称的 Hash 值
|
||||
size_t GetHashName() const;
|
||||
|
||||
// 获取 Z 轴顺序
|
||||
/// \~chinese
|
||||
/// @brief 获取 Z 轴顺序
|
||||
int GetZOrder() const;
|
||||
|
||||
// 获取坐标
|
||||
/// \~chinese
|
||||
/// @brief 获取坐标
|
||||
Point const& GetPosition() const;
|
||||
|
||||
// 获取 x 坐标
|
||||
/// \~chinese
|
||||
/// @brief 获取 x 坐标
|
||||
float GetPositionX() const;
|
||||
|
||||
// 获取 y 坐标
|
||||
/// \~chinese
|
||||
/// @brief 获取 y 坐标
|
||||
float GetPositionY() const;
|
||||
|
||||
// 获取缩放比例
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放比例
|
||||
Point const& GetScale() const;
|
||||
|
||||
// 获取横向缩放比例
|
||||
/// \~chinese
|
||||
/// @brief 获取横向缩放比例
|
||||
float GetScaleX() const;
|
||||
|
||||
// 获取纵向缩放比例
|
||||
/// \~chinese
|
||||
/// @brief 获取纵向缩放比例
|
||||
float GetScaleY() const;
|
||||
|
||||
// 获取错切角度
|
||||
/// \~chinese
|
||||
/// @brief 获取错切角度
|
||||
Point const& GetSkew() const;
|
||||
|
||||
// 获取横向错切角度
|
||||
/// \~chinese
|
||||
/// @brief 获取横向错切角度
|
||||
float GetSkewX() const;
|
||||
|
||||
// 获取纵向错切角度
|
||||
/// \~chinese
|
||||
/// @brief 获取纵向错切角度
|
||||
float GetSkewY() const;
|
||||
|
||||
// 获取旋转角度
|
||||
/// \~chinese
|
||||
/// @brief 获取旋转角度
|
||||
float GetRotation() const;
|
||||
|
||||
// 获取宽度
|
||||
/// \~chinese
|
||||
/// @brief 获取宽度
|
||||
float GetWidth() const;
|
||||
|
||||
// 获取高度
|
||||
/// \~chinese
|
||||
/// @brief 获取高度
|
||||
float GetHeight() const;
|
||||
|
||||
// 获取大小
|
||||
/// \~chinese
|
||||
/// @brief 获取大小
|
||||
Size const& GetSize() const;
|
||||
|
||||
// 获取缩放后的宽度
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的宽度
|
||||
float GetScaledWidth() const;
|
||||
|
||||
// 获取缩放后的高度
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的高度
|
||||
float GetScaledHeight() const;
|
||||
|
||||
// 获取缩放后的大小
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的大小
|
||||
Size GetScaledSize() const;
|
||||
|
||||
// 获取锚点
|
||||
/// \~chinese
|
||||
/// @brief 获取锚点
|
||||
Point const& GetAnchor() const;
|
||||
|
||||
// 获取 x 方向锚点
|
||||
/// \~chinese
|
||||
/// @brief 获取 x 方向锚点
|
||||
float GetAnchorX() const;
|
||||
|
||||
// 获取 y 方向锚点
|
||||
/// \~chinese
|
||||
/// @brief 获取 y 方向锚点
|
||||
float GetAnchorY() const;
|
||||
|
||||
// 获取透明度
|
||||
/// \~chinese
|
||||
/// @brief 获取透明度
|
||||
float GetOpacity() const;
|
||||
|
||||
// 获取显示透明度
|
||||
/// \~chinese
|
||||
/// @brief 获取显示透明度
|
||||
float GetDisplayedOpacity() const;
|
||||
|
||||
// 获取变换
|
||||
/// \~chinese
|
||||
/// @brief 获取变换
|
||||
Transform GetTransform() const;
|
||||
|
||||
// 获取父角色
|
||||
/// \~chinese
|
||||
/// @brief 获取父角色
|
||||
Actor* GetParent() const;
|
||||
|
||||
// 获取所在舞台
|
||||
/// \~chinese
|
||||
/// @brief 获取所在舞台
|
||||
Stage* GetStage() const;
|
||||
|
||||
// 获取边框
|
||||
/// \~chinese
|
||||
/// @brief 获取边框
|
||||
virtual Rect GetBounds() const;
|
||||
|
||||
// 获取外切包围盒
|
||||
/// \~chinese
|
||||
/// @brief 获取外切包围盒
|
||||
virtual Rect GetBoundingBox() const;
|
||||
|
||||
// 获取二维变换矩阵
|
||||
/// \~chinese
|
||||
/// @brief 获取二维变换矩阵
|
||||
Matrix3x2 const& GetTransformMatrix() const;
|
||||
|
||||
// 获取二维变换的逆矩阵
|
||||
/// \~chinese
|
||||
/// @brief 获取二维变换的逆矩阵
|
||||
Matrix3x2 const& GetTransformInverseMatrix() const;
|
||||
|
||||
// 设置是否显示
|
||||
void SetVisible(
|
||||
bool val
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置角色是否可见
|
||||
void SetVisible(bool val);
|
||||
|
||||
// 设置名称
|
||||
void SetName(
|
||||
String const& name
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置名称
|
||||
void SetName(String const& name);
|
||||
|
||||
// 设置坐标
|
||||
virtual void SetPosition(
|
||||
Point const& point
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置坐标
|
||||
virtual void SetPosition(Point const& point);
|
||||
|
||||
// 设置坐标
|
||||
void SetPosition(
|
||||
float x,
|
||||
float y
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置坐标
|
||||
void SetPosition(float x, float y);
|
||||
|
||||
// 设置横坐标
|
||||
void SetPositionX(
|
||||
float x
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置横坐标
|
||||
void SetPositionX(float x);
|
||||
|
||||
// 设置纵坐标
|
||||
void SetPositionY(
|
||||
float y
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置纵坐标
|
||||
void SetPositionY(float y);
|
||||
|
||||
// 移动坐标
|
||||
void Move(
|
||||
Vec2 const& v
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 移动坐标
|
||||
void Move(Vec2 const& v);
|
||||
|
||||
// 移动坐标
|
||||
void Move(
|
||||
float vx,
|
||||
float vy
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 移动坐标
|
||||
void Move(float vx, float vy);
|
||||
|
||||
// 设置缩放比例
|
||||
// 默认为 (1.0, 1.0)
|
||||
virtual void SetScale(
|
||||
Vec2 const& scale
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
|
||||
virtual void SetScale(Vec2 const& scale);
|
||||
|
||||
// 设置缩放比例
|
||||
// 默认为 (1.0, 1.0)
|
||||
void SetScale(
|
||||
float scalex,
|
||||
float scaley
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
|
||||
void SetScale(float scalex, float scaley);
|
||||
|
||||
// 设置错切角度
|
||||
// 默认为 (0, 0)
|
||||
virtual void SetSkew(
|
||||
Vec2 const& skew
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置错切角度,默认为 (0, 0)
|
||||
virtual void SetSkew(Vec2 const& skew);
|
||||
|
||||
// 设置错切角度
|
||||
// 默认为 (0, 0)
|
||||
void SetSkew(
|
||||
float skewx,
|
||||
float skewy
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置错切角度,默认为 (0, 0)
|
||||
void SetSkew(float skewx, float skewy);
|
||||
|
||||
// 设置旋转角度
|
||||
// 默认为 0
|
||||
virtual void SetRotation(
|
||||
float rotation
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置旋转角度,默认为 0
|
||||
virtual void SetRotation(float rotation);
|
||||
|
||||
// 设置锚点位置
|
||||
// 默认为 (0, 0), 范围 [0, 1]
|
||||
virtual void SetAnchor(
|
||||
Vec2 const& anchor
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
|
||||
virtual void SetAnchor(Vec2 const& anchor);
|
||||
|
||||
// 设置锚点位置
|
||||
// 默认为 (0, 0), 范围 [0, 1]
|
||||
void SetAnchor(
|
||||
float anchorx,
|
||||
float anchory
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
|
||||
void SetAnchor(float anchorx, float anchory);
|
||||
|
||||
// 修改宽度
|
||||
virtual void SetWidth(
|
||||
float width
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 修改宽度
|
||||
virtual void SetWidth(float width);
|
||||
|
||||
// 修改高度
|
||||
virtual void SetHeight(
|
||||
float height
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 修改高度
|
||||
virtual void SetHeight(float height);
|
||||
|
||||
// 修改大小
|
||||
virtual void SetSize(
|
||||
Size const& size
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 修改大小
|
||||
virtual void SetSize(Size const& size);
|
||||
|
||||
// 修改大小
|
||||
void SetSize(
|
||||
float width,
|
||||
float height
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 修改大小
|
||||
void SetSize(float width, float height);
|
||||
|
||||
// 设置透明度
|
||||
// 默认为 1.0, 范围 [0, 1]
|
||||
virtual void SetOpacity(
|
||||
float opacity
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
|
||||
virtual void SetOpacity(float opacity);
|
||||
|
||||
// 启用或禁用级联透明度
|
||||
void SetCascadeOpacityEnabled(
|
||||
bool enabled
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 启用或禁用级联透明度
|
||||
void SetCascadeOpacityEnabled(bool enabled);
|
||||
|
||||
// 设置二维仿射变换
|
||||
void SetTransform(
|
||||
Transform const& transform
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置二维仿射变换
|
||||
void SetTransform(Transform const& transform);
|
||||
|
||||
// 设置 Z 轴顺序
|
||||
// 默认为 0
|
||||
void SetZOrder(
|
||||
int zorder
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置 Z 轴顺序,默认为 0
|
||||
void SetZOrder(int zorder);
|
||||
|
||||
// 是否可响应 (鼠标 Hover | Out | Click 消息)
|
||||
// 默认为 false
|
||||
void SetResponsible(
|
||||
bool enable
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置角色是否可响应,默认为 false
|
||||
/// @details 可响应的角色会收到鼠标的 Hover | Out | Click 消息
|
||||
void SetResponsible(bool enable);
|
||||
|
||||
// 添加子角色
|
||||
void AddChild(
|
||||
ActorPtr child,
|
||||
int zorder = 0
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加子角色
|
||||
void AddChild(ActorPtr child, int zorder = 0);
|
||||
|
||||
// 添加子角色
|
||||
void AddChild(
|
||||
Actor* child,
|
||||
int zorder = 0
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加子角色
|
||||
void AddChild(Actor* child, int zorder = 0);
|
||||
|
||||
// 添加多个子角色
|
||||
void AddChildren(
|
||||
Vector<ActorPtr> const& children
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加多个子角色
|
||||
void AddChildren(Vector<ActorPtr> const& children);
|
||||
|
||||
// 获取名称相同的子角色
|
||||
Actor* GetChild(
|
||||
String const& name
|
||||
) const;
|
||||
/// \~chinese
|
||||
/// @brief 获取名称相同的子角色
|
||||
Actor* GetChild(String const& name) const;
|
||||
|
||||
// 获取所有名称相同的子角色
|
||||
Vector<ActorPtr> GetChildren(
|
||||
String const& name
|
||||
) const;
|
||||
/// \~chinese
|
||||
/// @brief 获取所有名称相同的子角色
|
||||
Vector<ActorPtr> GetChildren(String const& name) const;
|
||||
|
||||
// 获取全部子角色
|
||||
/// \~chinese
|
||||
/// @brief 获取全部子角色
|
||||
Children& GetAllChildren();
|
||||
|
||||
// 获取全部子角色
|
||||
/// \~chinese
|
||||
/// @brief 获取全部子角色
|
||||
Children const& GetAllChildren() const;
|
||||
|
||||
// 移除子角色
|
||||
void RemoveChild(
|
||||
ActorPtr child
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 移除子角色
|
||||
void RemoveChild(ActorPtr child);
|
||||
|
||||
// 移除子角色
|
||||
void RemoveChild(
|
||||
Actor* child
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 移除子角色
|
||||
void RemoveChild(Actor* child);
|
||||
|
||||
// 移除所有名称相同的子角色
|
||||
void RemoveChildren(
|
||||
String const& child_name
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 移除所有名称相同的子角色
|
||||
void RemoveChildren(String const& child_name);
|
||||
|
||||
// 移除所有角色
|
||||
/// \~chinese
|
||||
/// @brief 移除所有角色
|
||||
void RemoveAllChildren();
|
||||
|
||||
// 从父角色移除
|
||||
/// \~chinese
|
||||
/// @brief 从父角色移除
|
||||
void RemoveFromParent();
|
||||
|
||||
// 判断点是否在角色内
|
||||
/// \~chinese
|
||||
/// @brief 判断点是否在角色内
|
||||
virtual bool ContainsPoint(const Point& point) const;
|
||||
|
||||
// 暂停角色更新
|
||||
/// \~chinese
|
||||
/// @brief 暂停角色更新
|
||||
void PauseUpdating();
|
||||
|
||||
// 继续角色更新
|
||||
/// \~chinese
|
||||
/// @brief 继续角色更新
|
||||
void ResumeUpdating();
|
||||
|
||||
// 角色更新是否暂停
|
||||
/// \~chinese
|
||||
/// @brief 角色更新是否暂停
|
||||
bool IsUpdatePausing() const;
|
||||
|
||||
// 设置更新时的回调函数
|
||||
/// \~chinese
|
||||
/// @brief 设置更新时的回调函数
|
||||
void SetCallbackOnUpdate(UpdateCallback const& cb);
|
||||
|
||||
// 获取更新时的回调函数
|
||||
/// \~chinese
|
||||
/// @brief 获取更新时的回调函数
|
||||
UpdateCallback GetCallbackOnUpdate() const;
|
||||
|
||||
// 渲染角色边界
|
||||
/// \~chinese
|
||||
/// @brief 渲染角色边界
|
||||
void ShowBorder(bool show);
|
||||
|
||||
// 事件分发
|
||||
/// \~chinese
|
||||
/// @brief 分发事件
|
||||
void Dispatch(Event& evt) override;
|
||||
|
||||
// 设置默认锚点
|
||||
static void SetDefaultAnchor(
|
||||
float anchor_x,
|
||||
float anchor_y
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置默认锚点
|
||||
static void SetDefaultAnchor(float anchor_x, float anchor_y);
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 更新自身和所有子角色
|
||||
virtual void Update(Duration dt);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 渲染自身和所有子角色
|
||||
virtual void Render(RenderTarget* rt);
|
||||
|
||||
virtual void PrepareRender(RenderTarget* rt);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 绘制自身和所有子角色的边界
|
||||
virtual void RenderBorder(RenderTarget* rt);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 检查是否在渲染目标的视区内
|
||||
virtual bool CheckVisibilty(RenderTarget* rt) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 渲染前初始化渲染目标状态,仅当 CheckVisibilty 返回真时调用该函数
|
||||
virtual void PrepareToRender(RenderTarget* rt);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 更新自己的二维变换,并通知所有子角色
|
||||
void UpdateTransform() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 更新自己和所有子角色的透明度
|
||||
void UpdateOpacity();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 将所有子角色按Z轴顺序排序
|
||||
void Reorder();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置节点所在舞台
|
||||
void SetStage(Stage* stage);
|
||||
|
||||
private:
|
||||
|
|
@ -421,6 +464,9 @@ namespace kiwano
|
|||
mutable Matrix3x2 transform_matrix_inverse_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
inline void Actor::OnUpdate(Duration dt)
|
||||
{
|
||||
KGE_NOT_USED(dt);
|
||||
|
|
|
|||
|
|
@ -27,11 +27,8 @@ namespace kiwano
|
|||
Canvas::Canvas()
|
||||
: cache_expired_(false)
|
||||
, stroke_width_(1.0f)
|
||||
, fill_color_(0, 0, 0)
|
||||
, stroke_color_(Color::White)
|
||||
, stroke_style_(StrokeStyle::Miter)
|
||||
{
|
||||
Renderer::GetInstance()->CreateTextureRenderTarget(rt_);
|
||||
}
|
||||
|
||||
Canvas::~Canvas()
|
||||
|
|
@ -40,12 +37,14 @@ namespace kiwano
|
|||
|
||||
void Canvas::BeginDraw()
|
||||
{
|
||||
rt_.BeginDraw();
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->BeginDraw();
|
||||
}
|
||||
|
||||
void Canvas::EndDraw()
|
||||
{
|
||||
rt_.EndDraw();
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->EndDraw();
|
||||
cache_expired_ = true;
|
||||
}
|
||||
|
||||
|
|
@ -53,58 +52,19 @@ namespace kiwano
|
|||
{
|
||||
UpdateCache();
|
||||
|
||||
if (texture_cached_.IsValid())
|
||||
if (texture_cached_ && texture_cached_->IsValid())
|
||||
{
|
||||
PrepareRender(rt);
|
||||
PrepareToRender(rt);
|
||||
|
||||
Rect bitmap_rect(0.f, 0.f, texture_cached_.GetWidth(), texture_cached_.GetHeight());
|
||||
rt->DrawTexture(texture_cached_, bitmap_rect, bitmap_rect);
|
||||
Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight());
|
||||
rt->DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::SetStrokeColor(Color const& color)
|
||||
void Canvas::SetBrush(BrushPtr brush)
|
||||
{
|
||||
stroke_color_ = color;
|
||||
}
|
||||
|
||||
void Canvas::SetFillColor(Color const& color)
|
||||
{
|
||||
fill_color_ = color;
|
||||
}
|
||||
|
||||
void Canvas::SetStrokeWidth(float width)
|
||||
{
|
||||
stroke_width_ = std::max(width, 0.f);
|
||||
}
|
||||
|
||||
void Canvas::SetStrokeStyle(StrokeStyle stroke_style)
|
||||
{
|
||||
stroke_style_ = stroke_style;
|
||||
}
|
||||
|
||||
void Canvas::SetTextFont(Font const& font)
|
||||
{
|
||||
text_font_ = font;
|
||||
}
|
||||
|
||||
void Canvas::SetTextStyle(TextStyle const & text_style)
|
||||
{
|
||||
text_style_ = text_style;
|
||||
}
|
||||
|
||||
void Canvas::SetBrushOpacity(float opacity)
|
||||
{
|
||||
rt_.SetOpacity(opacity);
|
||||
}
|
||||
|
||||
Color Canvas::GetStrokeColor() const
|
||||
{
|
||||
return stroke_color_;
|
||||
}
|
||||
|
||||
Color Canvas::GetFillColor() const
|
||||
{
|
||||
return fill_color_;
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(brush);
|
||||
}
|
||||
|
||||
float Canvas::GetStrokeWidth() const
|
||||
|
|
@ -112,45 +72,47 @@ namespace kiwano
|
|||
return stroke_width_;
|
||||
}
|
||||
|
||||
float Canvas::GetBrushOpacity() const
|
||||
{
|
||||
return rt_.GetOpacity();
|
||||
}
|
||||
|
||||
void Canvas::SetBrushTransform(Transform const& transform)
|
||||
{
|
||||
rt_.SetTransform(transform.ToMatrix());
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetTransform(transform.ToMatrix());
|
||||
}
|
||||
|
||||
void Canvas::SetBrushTransform(Matrix3x2 const & transform)
|
||||
{
|
||||
rt_.SetTransform(transform);
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetTransform(transform);
|
||||
}
|
||||
|
||||
void Canvas::PushLayerArea(LayerArea& area)
|
||||
{
|
||||
rt_.PushLayer(area);
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->PushLayer(area);
|
||||
}
|
||||
|
||||
void Canvas::PopLayerArea()
|
||||
{
|
||||
rt_.PopLayer();
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->PopLayer();
|
||||
}
|
||||
|
||||
void Canvas::PushClipRect(Rect const& clip_rect)
|
||||
{
|
||||
rt_.PushClipRect(clip_rect);
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->PushClipRect(clip_rect);
|
||||
}
|
||||
|
||||
void Canvas::PopClipRect()
|
||||
{
|
||||
rt_.PopClipRect();
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->PopClipRect();
|
||||
}
|
||||
|
||||
void Canvas::DrawLine(Point const& begin, Point const& end)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(stroke_color_);
|
||||
rt_.DrawLine(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(stroke_brush_);
|
||||
rt_->DrawLine(
|
||||
begin,
|
||||
end,
|
||||
stroke_width_,
|
||||
|
|
@ -161,8 +123,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::DrawCircle(Point const& center, float radius)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(stroke_color_);
|
||||
rt_.DrawEllipse(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(stroke_brush_);
|
||||
rt_->DrawEllipse(
|
||||
center,
|
||||
Vec2(radius, radius),
|
||||
stroke_width_,
|
||||
|
|
@ -173,8 +136,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(stroke_color_);
|
||||
rt_.DrawEllipse(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(stroke_brush_);
|
||||
rt_->DrawEllipse(
|
||||
center,
|
||||
radius,
|
||||
stroke_width_,
|
||||
|
|
@ -185,8 +149,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::DrawRect(Rect const& rect)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(stroke_color_);
|
||||
rt_.DrawRectangle(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(stroke_brush_);
|
||||
rt_->DrawRectangle(
|
||||
rect,
|
||||
stroke_width_,
|
||||
stroke_style_
|
||||
|
|
@ -196,8 +161,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(stroke_color_);
|
||||
rt_.DrawRoundedRectangle(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(stroke_brush_);
|
||||
rt_->DrawRoundedRectangle(
|
||||
rect,
|
||||
radius,
|
||||
stroke_width_,
|
||||
|
|
@ -208,8 +174,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::FillCircle(Point const& center, float radius)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(fill_color_);
|
||||
rt_.FillEllipse(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(fill_brush_);
|
||||
rt_->FillEllipse(
|
||||
center,
|
||||
Vec2(radius, radius)
|
||||
);
|
||||
|
|
@ -218,8 +185,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::FillEllipse(Point const& center, Vec2 const& radius)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(fill_color_);
|
||||
rt_.FillEllipse(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(fill_brush_);
|
||||
rt_->FillEllipse(
|
||||
center,
|
||||
radius
|
||||
);
|
||||
|
|
@ -228,8 +196,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::FillRect(Rect const& rect)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(fill_color_);
|
||||
rt_.FillRectangle(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(fill_brush_);
|
||||
rt_->FillRectangle(
|
||||
rect
|
||||
);
|
||||
cache_expired_ = true;
|
||||
|
|
@ -237,31 +206,40 @@ namespace kiwano
|
|||
|
||||
void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius)
|
||||
{
|
||||
rt_.SetDefaultBrushColor(fill_color_);
|
||||
rt_.FillRoundedRectangle(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(fill_brush_);
|
||||
rt_->FillRoundedRectangle(
|
||||
rect,
|
||||
radius
|
||||
);
|
||||
cache_expired_ = true;
|
||||
}
|
||||
|
||||
void Canvas::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect)
|
||||
void Canvas::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect)
|
||||
{
|
||||
if (texture.IsValid())
|
||||
if (texture)
|
||||
{
|
||||
rt_.DrawTexture(texture, src_rect, dest_rect);
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->DrawTexture(*texture, src_rect, dest_rect);
|
||||
cache_expired_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::DrawText(String const& text, Point const& point)
|
||||
void Canvas::DrawTextLayout(String const& text, Point const& point)
|
||||
{
|
||||
if (text.empty())
|
||||
return;
|
||||
|
||||
TextLayout layout(text, text_font_, text_style_);
|
||||
TextLayout layout;
|
||||
layout.SetStyle(text_style_);
|
||||
layout.SetText(text);
|
||||
DrawTextLayout(layout, point);
|
||||
}
|
||||
|
||||
rt_.DrawTextLayout(layout, point);
|
||||
void Canvas::DrawTextLayout(TextLayout const& layout, Point const& point)
|
||||
{
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->DrawTextLayout(layout, point);
|
||||
}
|
||||
|
||||
void Canvas::BeginPath(Point const& begin_pos)
|
||||
|
|
@ -289,15 +267,16 @@ namespace kiwano
|
|||
geo_sink_.AddBezier(point1, point2, point3);
|
||||
}
|
||||
|
||||
void Canvas::AddArc(Point const & point, Point const & radius, float rotation, bool clockwise, bool is_small)
|
||||
void Canvas::AddArc(Point const & point, Size const & radius, float rotation, bool clockwise, bool is_small)
|
||||
{
|
||||
geo_sink_.AddArc(point, radius, rotation, clockwise, is_small);
|
||||
}
|
||||
|
||||
void Canvas::StrokePath()
|
||||
{
|
||||
rt_.SetDefaultBrushColor(stroke_color_);
|
||||
rt_.DrawGeometry(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(stroke_brush_);
|
||||
rt_->DrawGeometry(
|
||||
geo_sink_.GetGeometry(),
|
||||
stroke_width_,
|
||||
stroke_style_
|
||||
|
|
@ -307,8 +286,9 @@ namespace kiwano
|
|||
|
||||
void Canvas::FillPath()
|
||||
{
|
||||
rt_.SetDefaultBrushColor(fill_color_);
|
||||
rt_.FillGeometry(
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->SetCurrentBrush(fill_brush_);
|
||||
rt_->FillGeometry(
|
||||
geo_sink_.GetGeometry()
|
||||
);
|
||||
cache_expired_ = true;
|
||||
|
|
@ -316,28 +296,57 @@ namespace kiwano
|
|||
|
||||
void Canvas::Clear()
|
||||
{
|
||||
rt_.Clear();
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->Clear();
|
||||
cache_expired_ = true;
|
||||
}
|
||||
|
||||
void Canvas::Clear(Color const& clear_color)
|
||||
{
|
||||
rt_.Clear(clear_color);
|
||||
InitRenderTargetAndBrushs();
|
||||
rt_->Clear(clear_color);
|
||||
cache_expired_ = true;
|
||||
}
|
||||
|
||||
Texture Canvas::ExportToTexture() const
|
||||
TexturePtr Canvas::ExportToTexture() const
|
||||
{
|
||||
UpdateCache();
|
||||
return texture_cached_;
|
||||
}
|
||||
|
||||
void Canvas::InitRenderTargetAndBrushs()
|
||||
{
|
||||
if (!rt_)
|
||||
{
|
||||
Renderer::instance().CreateTextureRenderTarget(rt_);
|
||||
}
|
||||
|
||||
if (!stroke_brush_)
|
||||
{
|
||||
stroke_brush_ = new Brush;
|
||||
stroke_brush_->SetColor(Color::White);
|
||||
}
|
||||
|
||||
if (!fill_brush_)
|
||||
{
|
||||
fill_brush_ = new Brush;
|
||||
fill_brush_->SetColor(Color::White);
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::UpdateCache() const
|
||||
{
|
||||
if (cache_expired_)
|
||||
if (cache_expired_ && rt_)
|
||||
{
|
||||
texture_cached_ = rt_.GetOutput();
|
||||
cache_expired_ = false;
|
||||
if (!texture_cached_)
|
||||
{
|
||||
texture_cached_ = new Texture;
|
||||
}
|
||||
|
||||
if (rt_->GetOutput(*texture_cached_))
|
||||
{
|
||||
cache_expired_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,235 +21,314 @@
|
|||
#pragma once
|
||||
#include <kiwano/2d/Actor.h>
|
||||
#include <kiwano/renderer/RenderTarget.h>
|
||||
|
||||
#ifdef DrawText
|
||||
# undef DrawText
|
||||
#endif
|
||||
#include <kiwano/renderer/GeometrySink.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
// 画布
|
||||
KGE_DECLARE_SMART_PTR(Canvas);
|
||||
|
||||
/**
|
||||
* \addtogroup Actors
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 画布,用于绘制图元
|
||||
*/
|
||||
class KGE_API Canvas
|
||||
: public Actor
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 构建空画布
|
||||
Canvas();
|
||||
|
||||
virtual ~Canvas();
|
||||
|
||||
// 开始绘图
|
||||
/// \~chinese
|
||||
/// @brief 开始绘图
|
||||
void BeginDraw();
|
||||
|
||||
// 结束绘图
|
||||
/// \~chinese
|
||||
/// @brief 结束绘图
|
||||
void EndDraw();
|
||||
|
||||
// 画直线
|
||||
void DrawLine(
|
||||
Point const& begin,
|
||||
Point const& end
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 画线段
|
||||
/// @param begin 线段起点
|
||||
/// @param end 线段终点
|
||||
void DrawLine(Point const& begin, Point const& end);
|
||||
|
||||
// 画圆形边框
|
||||
void DrawCircle(
|
||||
Point const& center,
|
||||
float radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 画圆形边框
|
||||
/// @param center 圆形原点
|
||||
/// @param radius 圆形半径
|
||||
void DrawCircle(Point const& center, float radius);
|
||||
|
||||
// 画椭圆形边框
|
||||
void DrawEllipse(
|
||||
Point const& center,
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 画椭圆形边框
|
||||
/// @param center 椭圆原点
|
||||
/// @param radius 椭圆半径
|
||||
void DrawEllipse(Point const& center, Vec2 const& radius);
|
||||
|
||||
// 画矩形边框
|
||||
void DrawRect(
|
||||
Rect const& rect
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 画矩形边框
|
||||
/// @param rect 矩形
|
||||
void DrawRect(Rect const& rect);
|
||||
|
||||
// 画圆角矩形边框
|
||||
void DrawRoundedRect(
|
||||
Rect const& rect,
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 画圆角矩形边框
|
||||
/// @param rect 矩形
|
||||
/// @param radius 矩形圆角半径
|
||||
void DrawRoundedRect(Rect const& rect, Vec2 const& radius);
|
||||
|
||||
// 填充圆形
|
||||
void FillCircle(
|
||||
Point const& center,
|
||||
float radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 填充圆形
|
||||
/// @param center 圆形原点
|
||||
/// @param radius 圆形半径
|
||||
void FillCircle(Point const& center, float radius);
|
||||
|
||||
// 填充椭圆形
|
||||
void FillEllipse(
|
||||
Point const& center,
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 填充椭圆形
|
||||
/// @param center 椭圆原点
|
||||
/// @param radius 椭圆半径
|
||||
void FillEllipse(Point const& center, Vec2 const& radius);
|
||||
|
||||
// 填充矩形
|
||||
void FillRect(
|
||||
Rect const& rect
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 填充矩形
|
||||
/// @param rect 矩形
|
||||
void FillRect(Rect const& rect);
|
||||
|
||||
// 填充圆角矩形
|
||||
void FillRoundedRect(
|
||||
Rect const& rect,
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 填充圆角矩形
|
||||
/// @param rect 矩形
|
||||
/// @param radius 矩形圆角半径
|
||||
void FillRoundedRect(Rect const& rect, Vec2 const& radius);
|
||||
|
||||
// 画图
|
||||
void DrawTexture(
|
||||
Texture const& texture,
|
||||
const Rect* src_rect = nullptr,
|
||||
const Rect* dest_rect = nullptr
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 绘制纹理
|
||||
/// @param texture 纹理
|
||||
/// @param src_rect 纹理裁剪区域
|
||||
/// @param dest_rect 绘制目标区域
|
||||
void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
|
||||
|
||||
// 画文字
|
||||
void DrawText(
|
||||
String const& text, /* 文字 */
|
||||
Point const& point /* 文字位置 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 绘制文字布局
|
||||
/// @param text 文字
|
||||
/// @param point 绘制文字的位置
|
||||
void DrawTextLayout(String const& text, Point const& point);
|
||||
|
||||
// 开始绘制路径
|
||||
void BeginPath(
|
||||
Point const& begin_pos /* 路径起始点 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 绘制文字布局
|
||||
/// @param layout 文字布局
|
||||
/// @param point 绘制布局的位置
|
||||
void DrawTextLayout(TextLayout const& layout, Point const& point);
|
||||
|
||||
// 结束路径
|
||||
void EndPath(
|
||||
bool closed = true /* 路径是否闭合 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 开始绘制路径
|
||||
/// @param begin_pos 路径起始点
|
||||
void BeginPath(Point const& begin_pos);
|
||||
|
||||
// 添加一条线段
|
||||
void AddLine(
|
||||
Point const& point /* 端点 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 结束路径
|
||||
/// @param closed 路径是否闭合
|
||||
void EndPath(bool closed = false);
|
||||
|
||||
// 添加多条线段
|
||||
void AddLines(
|
||||
Vector<Point> const& points
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加一条线段
|
||||
/// @param point 端点
|
||||
void AddLine(Point const& point);
|
||||
|
||||
// 添加一条三次方贝塞尔曲线
|
||||
void AddBezier(
|
||||
Point const& point1, /* 贝塞尔曲线的第一个控制点 */
|
||||
Point const& point2, /* 贝塞尔曲线的第二个控制点 */
|
||||
Point const& point3 /* 贝塞尔曲线的终点 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加多条线段
|
||||
/// @param points 端点集合
|
||||
void AddLines(Vector<Point> const& points);
|
||||
|
||||
// 添加弧线
|
||||
void AddArc(
|
||||
Point const& point, /* 终点 */
|
||||
Point const& radius, /* 椭圆半径 */
|
||||
float rotation, /* 椭圆旋转角度 */
|
||||
bool clockwise = true, /* 顺时针 or 逆时针 */
|
||||
bool is_small = true /* 是否取小于 180° 的弧 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加一条三次方贝塞尔曲线
|
||||
/// @param point1 贝塞尔曲线的第一个控制点
|
||||
/// @param point2 贝塞尔曲线的第二个控制点
|
||||
/// @param point3 贝塞尔曲线的终点
|
||||
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
|
||||
|
||||
// 路径描边
|
||||
/// \~chinese
|
||||
/// @brief 添加弧线
|
||||
/// @param point 终点
|
||||
/// @param radius 椭圆半径
|
||||
/// @param rotation 椭圆旋转角度
|
||||
/// @param clockwise 顺时针 or 逆时针
|
||||
/// @param is_small 是否取小于 180° 的弧
|
||||
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 以描边的方式绘制路径
|
||||
void StrokePath();
|
||||
|
||||
// 路径填充
|
||||
/// \~chinese
|
||||
/// @brief 以填充的方式绘制路径
|
||||
void FillPath();
|
||||
|
||||
// 清空画布
|
||||
/// \~chinese
|
||||
/// @brief 清空画布
|
||||
void Clear();
|
||||
|
||||
// 清空画布
|
||||
void Clear(
|
||||
Color const& clear_color
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 清空画布
|
||||
/// @param clear_color 清空颜色
|
||||
void Clear(Color const& clear_color);
|
||||
|
||||
// 设置填充颜色
|
||||
void SetFillColor(
|
||||
Color const& color
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置填充颜色
|
||||
/// @param color 填充颜色
|
||||
void SetFillColor(Color const& color);
|
||||
|
||||
// 设置轮廓颜色
|
||||
void SetStrokeColor(
|
||||
Color const& color
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置填充画刷
|
||||
/// @param[in] brush 填充画刷
|
||||
void SetFillBrush(BrushPtr brush);
|
||||
|
||||
// 设置轮廓宽度
|
||||
void SetStrokeWidth(
|
||||
float width
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置轮廓颜色
|
||||
/// @param color 轮廓颜色
|
||||
void SetStrokeColor(Color const& color);
|
||||
|
||||
// 设置轮廓样式
|
||||
void SetStrokeStyle(
|
||||
StrokeStyle stroke_style
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置轮廓画刷
|
||||
/// @param[in] brush 轮廓画刷
|
||||
void SetStrokeBrush(BrushPtr brush);
|
||||
|
||||
// 设置文字字体
|
||||
void SetTextFont(
|
||||
Font const& font
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置轮廓宽度
|
||||
/// @param width 轮廓宽度
|
||||
void SetStrokeWidth(float width);
|
||||
|
||||
// 设置文字画刷样式
|
||||
void SetTextStyle(
|
||||
TextStyle const& text_style
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置轮廓样式
|
||||
/// @param stroke_style 轮廓样式
|
||||
void SetStrokeStyle(StrokeStyle stroke_style);
|
||||
|
||||
// 设置画笔透明度
|
||||
void SetBrushOpacity(
|
||||
float opacity
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置文字画刷样式
|
||||
/// @param text_style 文字画刷样式
|
||||
void SetTextStyle(TextStyle const& text_style);
|
||||
|
||||
// 画笔二维变换
|
||||
void SetBrushTransform(
|
||||
Transform const& transform
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置画刷
|
||||
/// @param[in] brush 画刷
|
||||
void SetBrush(BrushPtr brush);
|
||||
|
||||
// 画笔二维变换
|
||||
void SetBrushTransform(
|
||||
Matrix3x2 const& transform
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置画刷二维变换
|
||||
/// @param transform 二维变换
|
||||
void SetBrushTransform(Transform const& transform);
|
||||
|
||||
// 设置图层
|
||||
void PushLayerArea(
|
||||
LayerArea& area
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置画刷二维变换矩阵
|
||||
/// @param transform 二维变换矩阵
|
||||
void SetBrushTransform(Matrix3x2 const& transform);
|
||||
|
||||
// 弹出图层
|
||||
/// \~chinese
|
||||
/// @brief 添加一个图层
|
||||
/// @param area 图层区域
|
||||
void PushLayerArea(LayerArea& area);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 删除最近添加的图层
|
||||
void PopLayerArea();
|
||||
|
||||
// 设置裁剪区域
|
||||
void PushClipRect(
|
||||
Rect const& clip_rect
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加一个裁剪区域
|
||||
/// @param clip_rect 裁剪矩形
|
||||
void PushClipRect(Rect const& clip_rect);
|
||||
|
||||
// 弹出裁剪区域
|
||||
/// \~chinese
|
||||
/// @brief 删除最近添加的裁剪区域
|
||||
void PopClipRect();
|
||||
|
||||
// 获取填充颜色
|
||||
Color GetFillColor() const;
|
||||
|
||||
// 获取轮廓颜色
|
||||
Color GetStrokeColor() const;
|
||||
|
||||
// 获取轮廓宽度
|
||||
/// \~chinese
|
||||
/// @brief 获取轮廓宽度
|
||||
float GetStrokeWidth() const;
|
||||
|
||||
// 获取画笔透明度
|
||||
float GetBrushOpacity() const;
|
||||
/// \~chinese
|
||||
/// @brief 获取填充画刷
|
||||
BrushPtr GetFillBrush() const;
|
||||
|
||||
// 导出为图片
|
||||
Texture ExportToTexture() const;
|
||||
/// \~chinese
|
||||
/// @brief 获取轮廓画刷
|
||||
BrushPtr GetStrokeBrush() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 导出纹理
|
||||
TexturePtr ExportToTexture() const;
|
||||
|
||||
void OnRender(RenderTarget* rt) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void InitRenderTargetAndBrushs();
|
||||
|
||||
void UpdateCache() const;
|
||||
|
||||
protected:
|
||||
float stroke_width_;
|
||||
Color fill_color_;
|
||||
Color stroke_color_;
|
||||
Font text_font_;
|
||||
TextStyle text_style_;
|
||||
StrokeStyle stroke_style_;
|
||||
GeometrySink geo_sink_;
|
||||
TextureRenderTarget rt_;
|
||||
private:
|
||||
float stroke_width_;
|
||||
TextStyle text_style_;
|
||||
StrokeStyle stroke_style_;
|
||||
GeometrySink geo_sink_;
|
||||
BrushPtr fill_brush_;
|
||||
BrushPtr stroke_brush_;
|
||||
|
||||
mutable bool cache_expired_;
|
||||
mutable Texture texture_cached_;
|
||||
mutable bool cache_expired_;
|
||||
mutable TexturePtr texture_cached_;
|
||||
mutable TextureRenderTargetPtr rt_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline void Canvas::SetStrokeWidth(float width)
|
||||
{
|
||||
stroke_width_ = std::max(width, 0.f);
|
||||
}
|
||||
|
||||
inline void Canvas::SetStrokeStyle(StrokeStyle stroke_style)
|
||||
{
|
||||
stroke_style_ = stroke_style;
|
||||
}
|
||||
|
||||
inline void Canvas::SetTextStyle(TextStyle const& text_style)
|
||||
{
|
||||
text_style_ = text_style;
|
||||
}
|
||||
|
||||
inline void Canvas::SetStrokeColor(Color const& color)
|
||||
{
|
||||
InitRenderTargetAndBrushs();
|
||||
stroke_brush_->SetColor(color);
|
||||
}
|
||||
|
||||
inline void Canvas::SetFillColor(Color const& color)
|
||||
{
|
||||
InitRenderTargetAndBrushs();
|
||||
fill_brush_->SetColor(color);
|
||||
}
|
||||
|
||||
inline void Canvas::SetFillBrush(BrushPtr brush)
|
||||
{
|
||||
fill_brush_ = brush;
|
||||
}
|
||||
|
||||
inline void Canvas::SetStrokeBrush(BrushPtr brush)
|
||||
{
|
||||
stroke_brush_ = brush;
|
||||
}
|
||||
|
||||
inline BrushPtr Canvas::GetFillBrush() const
|
||||
{
|
||||
return fill_brush_;
|
||||
}
|
||||
|
||||
inline BrushPtr Canvas::GetStrokeBrush() const
|
||||
{
|
||||
return stroke_brush_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/2d/DebugActor.h>
|
||||
#include <kiwano/2d/Text.h>
|
||||
#include <kiwano/renderer/Renderer.h>
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <psapi.h>
|
||||
|
||||
#pragma comment(lib, "psapi.lib")
|
||||
|
|
@ -31,7 +31,7 @@ namespace kiwano
|
|||
{
|
||||
class comma_numpunct : public std::numpunct<wchar_t>
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
virtual wchar_t do_thousands_sep() const override
|
||||
{
|
||||
return L',';
|
||||
|
|
@ -42,32 +42,34 @@ namespace kiwano
|
|||
return "\03";
|
||||
}
|
||||
};
|
||||
|
||||
std::locale comma_locale(std::locale(), new comma_numpunct);
|
||||
}
|
||||
|
||||
DebugActor::DebugActor()
|
||||
: background_color_(0.0f, 0.0f, 0.0f, 0.7f)
|
||||
{
|
||||
SetName(L"kiwano-debug-actor");
|
||||
SetPosition(Point{ 10, 10 });
|
||||
SetResponsible(true);
|
||||
SetCascadeOpacityEnabled(true);
|
||||
|
||||
debug_text_ = new Text;
|
||||
background_brush_ = new Brush;
|
||||
background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f));
|
||||
|
||||
debug_text_ = new TextActor;
|
||||
debug_text_->SetPosition(Point{ 10, 10 });
|
||||
this->AddChild(debug_text_);
|
||||
|
||||
Font font;
|
||||
font.family = L"Arial";
|
||||
font.size = 16.f;
|
||||
font.weight = FontWeight::Normal;
|
||||
debug_text_->SetFont(font);
|
||||
|
||||
TextStyle style;
|
||||
style.font_family = L"Arial";
|
||||
style.font_size = 16.f;
|
||||
style.font_weight = FontWeight::Normal;
|
||||
style.line_spacing = 20.f;
|
||||
debug_text_->SetStyle(style);
|
||||
debug_text_->SetFillColor(Color::White);
|
||||
|
||||
AddListener(event::MouseHover, [=](Event&) { SetOpacity(0.4f); });
|
||||
AddListener(event::MouseOut, [=](Event&) { SetOpacity(1.f); });
|
||||
AddListener<MouseHoverEvent>([=](Event&) { SetOpacity(0.4f); });
|
||||
AddListener<MouseOutEvent>([=](Event&) { SetOpacity(1.f); });
|
||||
}
|
||||
|
||||
DebugActor::~DebugActor()
|
||||
|
|
@ -76,9 +78,7 @@ namespace kiwano
|
|||
|
||||
void DebugActor::OnRender(RenderTarget* rt)
|
||||
{
|
||||
PrepareRender(rt);
|
||||
|
||||
rt->SetDefaultBrushColor(background_color_);
|
||||
rt->SetCurrentBrush(background_brush_);
|
||||
rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f });
|
||||
}
|
||||
|
||||
|
|
@ -94,24 +94,21 @@ namespace kiwano
|
|||
|
||||
StringStream ss;
|
||||
|
||||
{
|
||||
// For formatting integers with commas
|
||||
static std::locale comma_locale(std::locale(), new comma_numpunct);
|
||||
(void)ss.imbue(comma_locale);
|
||||
}
|
||||
// For formatting integers with commas
|
||||
(void)ss.imbue(comma_locale);
|
||||
|
||||
ss << "Fps: " << frame_time_.size() << std::endl;
|
||||
|
||||
#if defined(KGE_DEBUG)
|
||||
if (ObjectBase::IsTracingLeaks())
|
||||
{
|
||||
ss << "Objects: " << ObjectBase::__GetTracingObjects().size() << std::endl;
|
||||
ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
ss << "Render: " << Renderer::GetInstance()->GetStatus().duration.Milliseconds() << "ms" << std::endl;
|
||||
ss << "Render: " << Renderer::instance().GetStatus().duration.Milliseconds() << "ms" << std::endl;
|
||||
|
||||
ss << "Primitives / sec: " << std::fixed << Renderer::GetInstance()->GetStatus().primitives * frame_time_.size() << std::endl;
|
||||
ss << "Primitives / sec: " << std::fixed << Renderer::instance().GetStatus().primitives * frame_time_.size() << std::endl;
|
||||
|
||||
ss << "Memory: ";
|
||||
{
|
||||
|
|
@ -140,4 +137,9 @@ namespace kiwano
|
|||
}
|
||||
}
|
||||
|
||||
bool DebugActor::CheckVisibilty(RenderTarget* rt) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,21 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano/2d/Actor.h>
|
||||
#include <kiwano/2d/TextActor.h>
|
||||
#include <kiwano/renderer/Color.h>
|
||||
#include <kiwano/renderer/Brush.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
/**
|
||||
* \addtogroup Actors
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 调试节点
|
||||
*/
|
||||
class KGE_API DebugActor
|
||||
: public Actor
|
||||
{
|
||||
|
|
@ -36,8 +48,14 @@ namespace kiwano
|
|||
void OnUpdate(Duration dt) override;
|
||||
|
||||
protected:
|
||||
Color background_color_;
|
||||
TextPtr debug_text_;
|
||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
||||
|
||||
private:
|
||||
BrushPtr background_brush_;
|
||||
TextActorPtr debug_text_;
|
||||
Vector<Time> frame_time_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,25 +27,10 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
Frame::Frame(String const& file_path)
|
||||
{
|
||||
Load(file_path);
|
||||
}
|
||||
|
||||
Frame::Frame(Resource const& res)
|
||||
{
|
||||
Load(res);
|
||||
}
|
||||
|
||||
Frame::Frame(Texture const& texture)
|
||||
{
|
||||
SetTexture(texture);
|
||||
}
|
||||
|
||||
bool Frame::Load(String const& file_path)
|
||||
{
|
||||
Texture texture = TextureCache::GetInstance()->AddOrGetTexture(file_path);
|
||||
if (texture.IsValid())
|
||||
TexturePtr texture = TextureCache::instance().AddOrGetTexture(file_path);
|
||||
if (texture->IsValid())
|
||||
{
|
||||
SetTexture(texture);
|
||||
return true;
|
||||
|
|
@ -55,8 +40,8 @@ namespace kiwano
|
|||
|
||||
bool Frame::Load(Resource const& res)
|
||||
{
|
||||
Texture texture = TextureCache::GetInstance()->AddOrGetTexture(res);
|
||||
if (texture.IsValid())
|
||||
TexturePtr texture = TextureCache::instance().AddOrGetTexture(res);
|
||||
if (texture->IsValid())
|
||||
{
|
||||
SetTexture(texture);
|
||||
return true;
|
||||
|
|
@ -66,9 +51,9 @@ namespace kiwano
|
|||
|
||||
void Frame::SetCropRect(Rect const& crop_rect)
|
||||
{
|
||||
if (texture_.IsValid())
|
||||
if (texture_->IsValid())
|
||||
{
|
||||
auto bitmap_size = texture_.GetSize();
|
||||
auto bitmap_size = texture_->GetSize();
|
||||
crop_rect_.left_top.x = std::min(std::max(crop_rect.left_top.x, 0.f), bitmap_size.x);
|
||||
crop_rect_.left_top.y = std::min(std::max(crop_rect.left_top.y, 0.f), bitmap_size.y);
|
||||
crop_rect_.right_bottom.x = std::min(std::max(crop_rect.right_bottom.x, 0.f), bitmap_size.x);
|
||||
|
|
@ -76,14 +61,14 @@ namespace kiwano
|
|||
}
|
||||
}
|
||||
|
||||
void Frame::SetTexture(Texture const& texture)
|
||||
void Frame::SetTexture(TexturePtr texture)
|
||||
{
|
||||
texture_ = texture;
|
||||
if (texture_.IsValid())
|
||||
if (texture_->IsValid())
|
||||
{
|
||||
crop_rect_.left_top.x = crop_rect_.left_top.y = 0;
|
||||
crop_rect_.right_bottom.x = texture_.GetWidth();
|
||||
crop_rect_.right_bottom.y = texture_.GetHeight();
|
||||
crop_rect_.right_bottom.x = texture_->GetWidth();
|
||||
crop_rect_.right_bottom.y = texture_->GetHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,63 +24,78 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
// 帧图像
|
||||
KGE_DECLARE_SMART_PTR(Frame);
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 图像帧
|
||||
*/
|
||||
class KGE_API Frame
|
||||
: public ObjectBase
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 构建空图像帧
|
||||
Frame();
|
||||
|
||||
explicit Frame(
|
||||
String const& file_path
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载图像
|
||||
/// @param file_path 图像路径
|
||||
bool Load(String const& file_path);
|
||||
|
||||
explicit Frame(
|
||||
Resource const& res
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载图像
|
||||
/// @param res 图像资源
|
||||
bool Load(Resource const& res);
|
||||
|
||||
explicit Frame(
|
||||
Texture const& texture
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 裁剪图像帧为矩形
|
||||
/// @param crop_rect 裁剪矩形定义
|
||||
void SetCropRect(Rect const& crop_rect);
|
||||
|
||||
bool Load(
|
||||
String const& file_path
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置纹理
|
||||
/// @param texture 纹理
|
||||
void SetTexture(TexturePtr texture);
|
||||
|
||||
bool Load(
|
||||
Resource const& res
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 是否有效
|
||||
bool IsValid() const;
|
||||
|
||||
// 裁剪矩形
|
||||
void SetCropRect(
|
||||
Rect const& crop_rect /* 裁剪矩形 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 获取宽度
|
||||
float GetWidth() const;
|
||||
|
||||
// 设置纹理
|
||||
void SetTexture(
|
||||
Texture const& texture
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 获取高度
|
||||
float GetHeight() const;
|
||||
|
||||
// 获取宽度
|
||||
float GetWidth() const { return crop_rect_.GetWidth(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取大小
|
||||
Size GetSize() const;
|
||||
|
||||
// 获取高度
|
||||
float GetHeight() const { return crop_rect_.GetHeight(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取裁剪位置
|
||||
Point GetCropPoint() const;
|
||||
|
||||
// 获取大小
|
||||
Size GetSize() const { return crop_rect_.GetSize(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取裁剪矩形
|
||||
Rect const& GetCropRect() const;
|
||||
|
||||
// 获取裁剪位置
|
||||
Point GetCropPoint() const { return crop_rect_.GetLeftTop(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取纹理
|
||||
TexturePtr GetTexture() const;
|
||||
|
||||
// 获取裁剪矩形
|
||||
inline Rect const& GetCropRect() const { return crop_rect_; }
|
||||
|
||||
// 获取纹理
|
||||
inline Texture const& GetTexture() const { return texture_; }
|
||||
|
||||
protected:
|
||||
Texture texture_;
|
||||
private:
|
||||
TexturePtr texture_;
|
||||
Rect crop_rect_;
|
||||
};
|
||||
|
||||
inline bool Frame::IsValid() const { return texture_ && texture_->IsValid(); }
|
||||
inline float Frame::GetWidth() const { return crop_rect_.GetWidth(); }
|
||||
inline float Frame::GetHeight() const { return crop_rect_.GetHeight(); }
|
||||
inline Size Frame::GetSize() const { return crop_rect_.GetSize(); }
|
||||
inline Point Frame::GetCropPoint() const { return crop_rect_.GetLeftTop(); }
|
||||
inline Rect const& Frame::GetCropRect() const { return crop_rect_; }
|
||||
inline TexturePtr Frame::GetTexture() const { return texture_; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/2d/FrameSequence.h>
|
||||
#include <kiwano/2d/Frame.h>
|
||||
#include <kiwano/core/Logger.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -70,6 +69,11 @@ namespace kiwano
|
|||
return frames_;
|
||||
}
|
||||
|
||||
size_t FrameSequence::GetFramesCount() const
|
||||
{
|
||||
return frames_.size();
|
||||
}
|
||||
|
||||
FrameSequencePtr FrameSequence::Clone() const
|
||||
{
|
||||
auto frame_seq = new (std::nothrow) FrameSequence;
|
||||
|
|
|
|||
|
|
@ -19,46 +19,65 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/2d/include-forwards.h>
|
||||
#include <kiwano/core/common.h>
|
||||
#include <kiwano/core/time.h>
|
||||
#include <kiwano/2d/Frame.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
// 序列帧
|
||||
KGE_DECLARE_SMART_PTR(FrameSequence);
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 序列帧
|
||||
*/
|
||||
class KGE_API FrameSequence
|
||||
: public ObjectBase
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 构建空序列帧
|
||||
FrameSequence();
|
||||
|
||||
explicit FrameSequence(
|
||||
Vector<FramePtr> const& frames /* 帧序列 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 构建序列帧
|
||||
/// @param frames 图像帧集合
|
||||
explicit FrameSequence(Vector<FramePtr> const& frames);
|
||||
|
||||
virtual ~FrameSequence();
|
||||
|
||||
// 添加关键帧
|
||||
void AddFrame(
|
||||
FramePtr frame
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加关键帧
|
||||
/// @param frame 图像帧
|
||||
void AddFrame(FramePtr frame);
|
||||
|
||||
// 添加多个关键帧
|
||||
void AddFrames(
|
||||
Vector<FramePtr> const& frames
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加多个关键帧
|
||||
/// @param frames 图像帧集合
|
||||
void AddFrames(Vector<FramePtr> const& frames);
|
||||
|
||||
// 获取关键帧
|
||||
/// \~chinese
|
||||
/// @brief 获取关键帧
|
||||
/// @param index 图像帧下标
|
||||
FramePtr GetFrame(size_t index) const;
|
||||
|
||||
// 获取关键帧
|
||||
/// \~chinese
|
||||
/// @brief 获取所有关键帧
|
||||
Vector<FramePtr> const& GetFrames() const;
|
||||
|
||||
// 获取帧动画的拷贝对象
|
||||
/// \~chinese
|
||||
/// @brief 获取关键帧数量
|
||||
size_t GetFramesCount() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取序列帧的拷贝对象
|
||||
FrameSequencePtr Clone() const;
|
||||
|
||||
// 获取帧动画的倒转
|
||||
/// \~chinese
|
||||
/// @brief 获取序列帧的倒转
|
||||
FrameSequencePtr Reverse() const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
Vector<FramePtr> frames_;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/2d/GifSprite.h>
|
||||
#include <kiwano/core/win32/helper.h>
|
||||
#include <kiwano/renderer/TextureCache.h>
|
||||
#include <kiwano/renderer/Renderer.h>
|
||||
|
||||
|
|
@ -33,37 +32,21 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
GifSprite::GifSprite(String const& file_path)
|
||||
{
|
||||
Load(file_path);
|
||||
}
|
||||
|
||||
GifSprite::GifSprite(Resource const& res)
|
||||
: GifSprite()
|
||||
{
|
||||
Load(res);
|
||||
}
|
||||
|
||||
GifSprite::GifSprite(GifImage gif)
|
||||
{
|
||||
Load(gif);
|
||||
}
|
||||
|
||||
bool GifSprite::Load(String const& file_path)
|
||||
{
|
||||
GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(file_path);
|
||||
return Load(texture);
|
||||
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(file_path);
|
||||
return Load(image);
|
||||
}
|
||||
|
||||
bool GifSprite::Load(Resource const& res)
|
||||
{
|
||||
GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(res);
|
||||
return Load(texture);
|
||||
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(res);
|
||||
return Load(image);
|
||||
}
|
||||
|
||||
bool GifSprite::Load(GifImage gif)
|
||||
bool GifSprite::Load(GifImagePtr gif)
|
||||
{
|
||||
if (gif.IsValid())
|
||||
if (gif && gif->IsValid())
|
||||
{
|
||||
gif_ = gif;
|
||||
|
||||
|
|
@ -71,14 +54,14 @@ namespace kiwano
|
|||
loop_count_ = 0;
|
||||
frame_.disposal_type = GifImage::DisposalType::None;
|
||||
|
||||
SetSize(Size{ static_cast<float>(gif_.GetWidthInPixels()), static_cast<float>(gif_.GetHeightInPixels()) });
|
||||
SetSize(Size{ static_cast<float>(gif_->GetWidthInPixels()), static_cast<float>(gif_->GetHeightInPixels()) });
|
||||
|
||||
if (!frame_rt_.IsValid())
|
||||
if (!frame_rt_)
|
||||
{
|
||||
Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_);
|
||||
Renderer::instance().CreateTextureRenderTarget(frame_rt_);
|
||||
}
|
||||
|
||||
if (gif_.GetFramesCount() > 0)
|
||||
if (gif_->GetFramesCount() > 0)
|
||||
{
|
||||
ComposeNextFrame();
|
||||
}
|
||||
|
|
@ -89,11 +72,11 @@ namespace kiwano
|
|||
|
||||
void GifSprite::OnRender(RenderTarget* rt)
|
||||
{
|
||||
if (frame_.raw.IsValid() && CheckVisibilty(rt))
|
||||
if (frame_to_render_ && CheckVisibilty(rt))
|
||||
{
|
||||
PrepareRender(rt);
|
||||
PrepareToRender(rt);
|
||||
|
||||
rt->DrawTexture(frame_.raw, &frame_.rect, nullptr);
|
||||
rt->DrawTexture(*frame_to_render_, &frame_.rect, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +84,7 @@ namespace kiwano
|
|||
{
|
||||
Actor::Update(dt);
|
||||
|
||||
if (gif_.IsValid() && animating_)
|
||||
if (gif_ && gif_->IsValid() && animating_)
|
||||
{
|
||||
frame_elapsed_ += dt;
|
||||
if (frame_.delay <= frame_elapsed_)
|
||||
|
|
@ -113,7 +96,7 @@ namespace kiwano
|
|||
}
|
||||
}
|
||||
|
||||
void GifSprite::SetGifImage(GifImage const& gif)
|
||||
void GifSprite::SetGifImage(GifImagePtr gif)
|
||||
{
|
||||
gif_ = gif;
|
||||
RestartAnimation();
|
||||
|
|
@ -129,7 +112,10 @@ namespace kiwano
|
|||
|
||||
void GifSprite::ComposeNextFrame()
|
||||
{
|
||||
if (frame_rt_.IsValid())
|
||||
KGE_ASSERT(frame_rt_);
|
||||
KGE_ASSERT(gif_);
|
||||
|
||||
if (frame_rt_->IsValid())
|
||||
{
|
||||
do
|
||||
{
|
||||
|
|
@ -137,7 +123,7 @@ namespace kiwano
|
|||
OverlayNextFrame();
|
||||
} while (frame_.delay.IsZero() && !IsLastFrame());
|
||||
|
||||
animating_ = (!EndOfAnimation() && gif_.GetFramesCount() > 1);
|
||||
animating_ = (!EndOfAnimation() && gif_->GetFramesCount() > 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,48 +136,51 @@ namespace kiwano
|
|||
break;
|
||||
|
||||
case GifImage::DisposalType::Background:
|
||||
{
|
||||
ClearCurrentFrameArea();
|
||||
break;
|
||||
}
|
||||
|
||||
case GifImage::DisposalType::Previous:
|
||||
{
|
||||
RestoreSavedFrame();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ThrowIfFailed(E_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
void GifSprite::OverlayNextFrame()
|
||||
{
|
||||
Renderer::GetInstance()->CreateGifImageFrame(frame_, gif_, next_index_);
|
||||
KGE_ASSERT(frame_rt_);
|
||||
KGE_ASSERT(gif_ && gif_->IsValid());
|
||||
|
||||
frame_ = gif_->GetFrame(next_index_);
|
||||
|
||||
if (frame_.disposal_type == GifImage::DisposalType::Previous)
|
||||
{
|
||||
SaveComposedFrame();
|
||||
}
|
||||
|
||||
if (frame_rt_.IsValid())
|
||||
if (frame_rt_->IsValid())
|
||||
{
|
||||
frame_rt_.BeginDraw();
|
||||
frame_rt_->BeginDraw();
|
||||
|
||||
if (next_index_ == 0)
|
||||
{
|
||||
loop_count_++;
|
||||
}
|
||||
|
||||
frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect);
|
||||
frame_rt_.EndDraw();
|
||||
|
||||
Texture frame_to_render = frame_rt_.GetOutput();
|
||||
if (frame_to_render.IsValid())
|
||||
if (frame_.texture)
|
||||
{
|
||||
frame_.raw = frame_to_render;
|
||||
next_index_ = (++next_index_) % gif_.GetFramesCount();
|
||||
frame_rt_->DrawTexture(*frame_.texture, nullptr, &frame_.rect);
|
||||
}
|
||||
|
||||
frame_rt_->EndDraw();
|
||||
|
||||
if (!frame_to_render_)
|
||||
{
|
||||
frame_to_render_ = new Texture;
|
||||
}
|
||||
|
||||
if (frame_rt_->GetOutput(*frame_to_render_))
|
||||
{
|
||||
next_index_ = (++next_index_) % gif_->GetFramesCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,63 +197,47 @@ namespace kiwano
|
|||
|
||||
void GifSprite::SaveComposedFrame()
|
||||
{
|
||||
Texture frame_to_be_saved = frame_rt_.GetOutput();
|
||||
KGE_ASSERT(frame_rt_);
|
||||
|
||||
HRESULT hr = frame_to_be_saved.IsValid() ? S_OK : E_FAIL;
|
||||
TexturePtr frame_to_be_saved = new Texture;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (frame_rt_->GetOutput(*frame_to_be_saved))
|
||||
{
|
||||
if (!saved_frame_.IsValid())
|
||||
if (!saved_frame_)
|
||||
{
|
||||
auto size = frame_to_be_saved.GetSizeInPixels();
|
||||
auto prop = D2D1::BitmapProperties(frame_to_be_saved.GetPixelFormat());
|
||||
|
||||
ComPtr<ID2D1Bitmap> saved_bitmap;
|
||||
hr = frame_rt_.GetRenderTarget()->CreateBitmap(D2D1::SizeU(size.x, size.y), prop, &saved_bitmap);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
saved_frame_.SetBitmap(saved_bitmap);
|
||||
}
|
||||
saved_frame_ = new Texture;
|
||||
frame_rt_->CreateTexture(*saved_frame_, frame_to_be_saved->GetSizeInPixels(), frame_to_be_saved->GetPixelFormat());
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
saved_frame_.CopyFrom(frame_to_be_saved);
|
||||
saved_frame_->CopyFrom(frame_to_be_saved);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr);
|
||||
}
|
||||
|
||||
void GifSprite::RestoreSavedFrame()
|
||||
{
|
||||
HRESULT hr = saved_frame_.IsValid() ? S_OK : E_FAIL;
|
||||
KGE_ASSERT(frame_rt_);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (saved_frame_)
|
||||
{
|
||||
Texture frame_to_copy_to = frame_rt_.GetOutput();
|
||||
TexturePtr frame_to_copy_to = new Texture;
|
||||
|
||||
hr = frame_to_copy_to.IsValid() ? S_OK : E_FAIL;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (frame_rt_->GetOutput(*frame_to_copy_to))
|
||||
{
|
||||
frame_to_copy_to.CopyFrom(saved_frame_);
|
||||
frame_to_copy_to->CopyFrom(saved_frame_);
|
||||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr);
|
||||
}
|
||||
|
||||
void GifSprite::ClearCurrentFrameArea()
|
||||
{
|
||||
frame_rt_.BeginDraw();
|
||||
KGE_ASSERT(frame_rt_);
|
||||
frame_rt_->BeginDraw();
|
||||
|
||||
frame_rt_.PushClipRect(frame_.rect);
|
||||
frame_rt_.Clear();
|
||||
frame_rt_.PopClipRect();
|
||||
frame_rt_->PushClipRect(frame_.rect);
|
||||
frame_rt_->Clear();
|
||||
frame_rt_->PopClipRect();
|
||||
|
||||
return frame_rt_.EndDraw();
|
||||
return frame_rt_->EndDraw();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,93 +26,145 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
// GIF 精灵
|
||||
KGE_DECLARE_SMART_PTR(GifSprite);
|
||||
|
||||
/**
|
||||
* \addtogroup Actors
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief GIF 精灵
|
||||
*/
|
||||
class KGE_API GifSprite
|
||||
: public Actor
|
||||
{
|
||||
public:
|
||||
using LoopDoneCallback = Function<void(int)>;
|
||||
/// \~chinese
|
||||
/// @brief GIF播放循环结束回调
|
||||
using LoopDoneCallback = Function<void(int /* times */)>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief GIF播放结束回调
|
||||
using DoneCallback = Function<void()>;
|
||||
|
||||
GifSprite();
|
||||
|
||||
GifSprite(
|
||||
String const& file_path
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载GIF图片
|
||||
/// @param file_path GIF图片路径
|
||||
bool Load(String const& file_path);
|
||||
|
||||
GifSprite(
|
||||
Resource const& res
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载GIF图片
|
||||
/// @param res GIF图片资源
|
||||
bool Load(Resource const& res);
|
||||
|
||||
GifSprite(
|
||||
GifImage gif
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 加载GIF图片
|
||||
/// @param gif GIF图片
|
||||
bool Load(GifImagePtr gif);
|
||||
|
||||
bool Load(
|
||||
String const& file_path
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置 GIF 动画循环次数
|
||||
void SetLoopCount(int loops);
|
||||
|
||||
bool Load(
|
||||
Resource const& res
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置 GIF 动画每次循环结束回调函数
|
||||
void SetLoopDoneCallback(LoopDoneCallback const& cb);
|
||||
|
||||
bool Load(
|
||||
GifImage gif
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置 GIF 动画结束回调函数
|
||||
void SetDoneCallback(DoneCallback const& cb);
|
||||
|
||||
// 设置 GIF 动画循环次数
|
||||
inline void SetLoopCount(int loops) { total_loop_count_ = loops; }
|
||||
/// \~chinese
|
||||
/// @brief 设置 GIF 图像
|
||||
void SetGifImage(GifImagePtr gif);
|
||||
|
||||
// 设置 GIF 动画每次循环结束回调函数
|
||||
inline void SetLoopDoneCallback(LoopDoneCallback const& cb) { loop_cb_ = cb; }
|
||||
|
||||
// 设置 GIF 动画结束回调函数
|
||||
inline void SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; }
|
||||
|
||||
// 设置 GIF 图像
|
||||
void SetGifImage(GifImage const& gif);
|
||||
|
||||
// 重新播放动画
|
||||
/// \~chinese
|
||||
/// @brief 重新播放 GIF 动画
|
||||
void RestartAnimation();
|
||||
|
||||
inline LoopDoneCallback GetLoopDoneCallback() const { return loop_cb_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取 GIF 动画循环结束回调
|
||||
LoopDoneCallback GetLoopDoneCallback() const;
|
||||
|
||||
inline DoneCallback GetDoneCallback() const { return done_cb_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取 GIF 动画播放结束回调
|
||||
DoneCallback GetDoneCallback() const;
|
||||
|
||||
inline GifImage const& GetGifImage() const { return gif_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取 GIF 图片
|
||||
GifImagePtr GetGifImage() const;
|
||||
|
||||
void OnRender(RenderTarget* rt) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void Update(Duration dt) override;
|
||||
|
||||
inline bool IsLastFrame() const { return (next_index_ == 0); }
|
||||
/// \~chinese
|
||||
/// @brief 是否是最后一帧
|
||||
bool IsLastFrame() const;
|
||||
|
||||
inline bool EndOfAnimation() const { return IsLastFrame() && loop_count_ == total_loop_count_ + 1; }
|
||||
/// \~chinese
|
||||
/// @brief 动画是否已结束
|
||||
bool EndOfAnimation() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 合成下一帧
|
||||
void ComposeNextFrame();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 解析当前图像帧
|
||||
void DisposeCurrentFrame();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 覆盖下一帧
|
||||
void OverlayNextFrame();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 保存合成后的图像帧
|
||||
void SaveComposedFrame();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 恢复已保存的图像帧
|
||||
void RestoreSavedFrame();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 清空当前图像区域
|
||||
void ClearCurrentFrameArea();
|
||||
|
||||
protected:
|
||||
bool animating_;
|
||||
int total_loop_count_;
|
||||
int loop_count_;
|
||||
size_t next_index_;
|
||||
Duration frame_elapsed_;
|
||||
LoopDoneCallback loop_cb_;
|
||||
DoneCallback done_cb_;
|
||||
GifImage gif_;
|
||||
GifImage::Frame frame_;
|
||||
Texture saved_frame_;
|
||||
TextureRenderTarget frame_rt_;
|
||||
private:
|
||||
bool animating_;
|
||||
int total_loop_count_;
|
||||
int loop_count_;
|
||||
size_t next_index_;
|
||||
Duration frame_elapsed_;
|
||||
LoopDoneCallback loop_cb_;
|
||||
DoneCallback done_cb_;
|
||||
GifImagePtr gif_;
|
||||
GifImage::Frame frame_;
|
||||
TexturePtr saved_frame_;
|
||||
TexturePtr frame_to_render_;
|
||||
TextureRenderTargetPtr frame_rt_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline void GifSprite::SetLoopCount(int loops) { total_loop_count_ = loops; }
|
||||
|
||||
inline void GifSprite::SetLoopDoneCallback(LoopDoneCallback const& cb) { loop_cb_ = cb; }
|
||||
|
||||
inline void GifSprite::SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; }
|
||||
|
||||
inline GifSprite::LoopDoneCallback GifSprite::GetLoopDoneCallback() const { return loop_cb_; }
|
||||
|
||||
inline GifSprite::DoneCallback GifSprite::GetDoneCallback() const { return done_cb_; }
|
||||
|
||||
inline GifImagePtr GifSprite::GetGifImage() const { return gif_; }
|
||||
|
||||
inline bool GifSprite::IsLastFrame() const { return (next_index_ == 0); }
|
||||
|
||||
inline bool GifSprite::EndOfAnimation() const { return IsLastFrame() && loop_count_ == total_loop_count_ + 1; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,16 +27,6 @@ namespace kiwano
|
|||
Layer::Layer()
|
||||
: swallow_(false)
|
||||
{
|
||||
auto handler = Closure(this, &Layer::HandleMessages);
|
||||
|
||||
AddListener(event::MouseDown, handler);
|
||||
AddListener(event::MouseUp, handler);
|
||||
AddListener(event::MouseMove, handler);
|
||||
AddListener(event::MouseWheel, handler);
|
||||
|
||||
AddListener(event::KeyDown, handler);
|
||||
AddListener(event::KeyUp, handler);
|
||||
AddListener(event::KeyChar, handler);
|
||||
}
|
||||
|
||||
Layer::~Layer()
|
||||
|
|
@ -84,50 +74,17 @@ namespace kiwano
|
|||
|
||||
void Layer::Render(RenderTarget* rt)
|
||||
{
|
||||
PrepareRender(rt);
|
||||
|
||||
rt->PushLayer(area_);
|
||||
|
||||
Actor::Render(rt);
|
||||
|
||||
rt->PopLayer();
|
||||
}
|
||||
|
||||
void Layer::HandleMessages(Event& evt)
|
||||
bool Layer::CheckVisibilty(RenderTarget* rt) const
|
||||
{
|
||||
if (evt.type == event::MouseDown)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<MouseDownEvent>();
|
||||
OnMouseButtonDown(real_evt->button, real_evt->pos);
|
||||
}
|
||||
else if (evt.type == event::MouseUp)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<MouseUpEvent>();
|
||||
OnMouseButtonUp(real_evt->button, real_evt->pos);
|
||||
}
|
||||
else if (evt.type == event::MouseMove)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<MouseMoveEvent>();
|
||||
OnMouseMoved(real_evt->pos);
|
||||
}
|
||||
else if (evt.type == event::MouseWheel)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<MouseWheelEvent>();
|
||||
OnMouseWheel(real_evt->wheel);
|
||||
}
|
||||
else if (evt.type == event::KeyDown)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<KeyDownEvent>();
|
||||
OnKeyDown(real_evt->code);
|
||||
}
|
||||
else if (evt.type == event::KeyUp)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<KeyUpEvent>();
|
||||
OnKeyUp(real_evt->code);
|
||||
}
|
||||
else if (evt.type == event::KeyChar)
|
||||
{
|
||||
auto real_evt = evt.SafeCast<KeyCharEvent>();
|
||||
OnChar(real_evt->value);
|
||||
}
|
||||
// Do not need to render Layer
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,22 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano/2d/Actor.h>
|
||||
#include <kiwano/2d/..\renderer\LayerArea.h>
|
||||
#include <kiwano/2d/..\renderer\RenderTarget.h>
|
||||
#include <kiwano/renderer/LayerArea.h>
|
||||
#include <kiwano/renderer/RenderTarget.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
KGE_DECLARE_SMART_PTR(Layer);
|
||||
|
||||
/**
|
||||
* \addtogroup Actors
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 图层
|
||||
*/
|
||||
class KGE_API Layer
|
||||
: public Actor
|
||||
{
|
||||
|
|
@ -33,49 +44,64 @@ namespace kiwano
|
|||
|
||||
virtual ~Layer();
|
||||
|
||||
// 重载下列函数以获取图层事件
|
||||
virtual void OnMouseButtonDown(MouseButton::Value btn, Point const& p) {}
|
||||
virtual void OnMouseButtonUp(MouseButton::Value btn, Point const& p) {}
|
||||
virtual void OnMouseMoved(Point const& p) {}
|
||||
virtual void OnMouseWheel(float wheel) {}
|
||||
virtual void OnKeyDown(int key) {}
|
||||
virtual void OnKeyUp(int key) {}
|
||||
virtual void OnChar(char c) {}
|
||||
/// \~chinese
|
||||
/// @brief 是否开启消息吞没
|
||||
bool IsSwallowEventsEnabled() const;
|
||||
|
||||
// 是否开启消息吞没
|
||||
inline bool IsSwallowEventsEnabled() const { return swallow_; }
|
||||
/// \~chinese
|
||||
/// @brief 设置消息吞没功能
|
||||
/// @param enabled 是否启用
|
||||
void SetSwallowEvents(bool enabled);
|
||||
|
||||
// 吞没消息
|
||||
inline void SetSwallowEvents(bool enabled) { swallow_ = enabled; }
|
||||
|
||||
// 设置裁剪区域
|
||||
/// \~chinese
|
||||
/// @brief 设置裁剪区域
|
||||
/// @param clip_rect 裁剪矩形
|
||||
void SetClipRect(Rect const& clip_rect);
|
||||
|
||||
// 设置图层透明度
|
||||
/// \~chinese
|
||||
/// @brief 设置图层透明度
|
||||
/// @param opacity 透明度
|
||||
void SetOpacity(float opacity) override;
|
||||
|
||||
// 设置几何蒙层
|
||||
/// \~chinese
|
||||
/// @brief 设置几何蒙层
|
||||
/// @param mask 蒙层的几何形状
|
||||
void SetMaskGeometry(Geometry const& mask);
|
||||
|
||||
// 设置几何蒙层的二维变换
|
||||
/// \~chinese
|
||||
/// @brief 设置几何蒙层的二维变换
|
||||
/// @param transform 应用于蒙层的二维变换
|
||||
void SetMaskTransform(Matrix3x2 const& transform);
|
||||
|
||||
// 设置图层区域
|
||||
inline void SetArea(LayerArea const& area) { area_ = area; }
|
||||
/// \~chinese
|
||||
/// @brief 设置图层区域
|
||||
/// @param area 图层区域属性
|
||||
void SetArea(LayerArea const& area);
|
||||
|
||||
// 获取图层区域
|
||||
inline LayerArea const& GetArea() const { return area_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取图层区域
|
||||
LayerArea const& GetArea() const;
|
||||
|
||||
public:
|
||||
void Dispatch(Event& evt) override;
|
||||
|
||||
protected:
|
||||
void Render(RenderTarget* rt) override;
|
||||
|
||||
void HandleMessages(Event& evt);
|
||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
bool swallow_;
|
||||
LayerArea area_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline bool Layer::IsSwallowEventsEnabled() const { return swallow_; }
|
||||
|
||||
inline void Layer::SetSwallowEvents(bool enabled) { swallow_ = enabled; }
|
||||
|
||||
inline void Layer::SetArea(LayerArea const& area) { area_ = area; }
|
||||
|
||||
inline LayerArea const& Layer::GetArea() const { return area_; }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,19 +25,11 @@
|
|||
namespace kiwano
|
||||
{
|
||||
ShapeActor::ShapeActor()
|
||||
: fill_color_(Color::White)
|
||||
, stroke_color_(Color(Color::Black, 0))
|
||||
, stroke_width_(1.f)
|
||||
: stroke_width_(1.f)
|
||||
, stroke_style_(StrokeStyle::Miter)
|
||||
{
|
||||
}
|
||||
|
||||
ShapeActor::ShapeActor(Geometry const& geometry)
|
||||
: ShapeActor()
|
||||
{
|
||||
SetGeometry(geometry);
|
||||
}
|
||||
|
||||
ShapeActor::~ShapeActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -49,7 +41,7 @@ namespace kiwano
|
|||
|
||||
Rect ShapeActor::GetBoundingBox() const
|
||||
{
|
||||
if (!geo_)
|
||||
if (!geo_.IsValid())
|
||||
return Rect{};
|
||||
|
||||
return geo_.GetBoundingBox(GetTransformMatrix());
|
||||
|
|
@ -57,17 +49,7 @@ namespace kiwano
|
|||
|
||||
bool ShapeActor::ContainsPoint(const Point& point) const
|
||||
{
|
||||
return geo_.ContainsPoint(point, GetTransformMatrix());
|
||||
}
|
||||
|
||||
void ShapeActor::SetFillColor(const Color & color)
|
||||
{
|
||||
fill_color_ = color;
|
||||
}
|
||||
|
||||
void ShapeActor::SetStrokeColor(const Color & color)
|
||||
{
|
||||
stroke_color_ = color;
|
||||
return geo_.ContainsPoint(point, &GetTransformMatrix());
|
||||
}
|
||||
|
||||
void ShapeActor::SetStrokeWidth(float width)
|
||||
|
|
@ -83,7 +65,7 @@ namespace kiwano
|
|||
void ShapeActor::SetGeometry(Geometry const& geometry)
|
||||
{
|
||||
geo_ = geometry;
|
||||
if (geo_)
|
||||
if (geo_.IsValid())
|
||||
{
|
||||
bounds_ = geo_.GetBoundingBox();
|
||||
SetSize(bounds_.GetSize());
|
||||
|
|
@ -97,22 +79,29 @@ namespace kiwano
|
|||
|
||||
void ShapeActor::OnRender(RenderTarget* rt)
|
||||
{
|
||||
if (geo_ && CheckVisibilty(rt))
|
||||
// Create default brush
|
||||
if (!fill_brush_)
|
||||
{
|
||||
PrepareRender(rt);
|
||||
|
||||
rt->SetDefaultBrushColor(stroke_color_);
|
||||
rt->DrawGeometry(
|
||||
geo_,
|
||||
stroke_width_ * 2, // twice width for widening
|
||||
stroke_style_
|
||||
);
|
||||
|
||||
rt->SetDefaultBrushColor(fill_color_);
|
||||
rt->FillGeometry(
|
||||
geo_
|
||||
);
|
||||
fill_brush_ = new Brush;
|
||||
fill_brush_->SetColor(Color::White);
|
||||
}
|
||||
|
||||
if (!stroke_brush_)
|
||||
{
|
||||
stroke_brush_ = new Brush;
|
||||
stroke_brush_->SetColor(Color::Transparent);
|
||||
}
|
||||
|
||||
rt->SetCurrentBrush(stroke_brush_);
|
||||
rt->DrawGeometry(geo_, stroke_width_ * 2 /* twice width for widening */, stroke_style_);
|
||||
|
||||
rt->SetCurrentBrush(fill_brush_);
|
||||
rt->FillGeometry(geo_);
|
||||
}
|
||||
|
||||
bool ShapeActor::CheckVisibilty(RenderTarget* rt) const
|
||||
{
|
||||
return geo_.IsValid() && Actor::CheckVisibilty(rt);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
|
@ -123,11 +112,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
LineActor::LineActor(Point const& begin, Point const& end)
|
||||
{
|
||||
SetLine(begin, end);
|
||||
}
|
||||
|
||||
LineActor::~LineActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -151,11 +135,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
RectActor::RectActor(Size const& size)
|
||||
{
|
||||
SetRectSize(size);
|
||||
}
|
||||
|
||||
RectActor::~RectActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -178,11 +157,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
RoundRectActor::RoundRectActor(Size const& size, Vec2 const& radius)
|
||||
{
|
||||
SetRoundedRect(size, radius);
|
||||
}
|
||||
|
||||
RoundRectActor::~RoundRectActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -217,11 +191,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
CircleActor::CircleActor(float radius)
|
||||
{
|
||||
SetRadius(radius);
|
||||
}
|
||||
|
||||
CircleActor::~CircleActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -244,11 +213,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
EllipseActor::EllipseActor(Vec2 const& radius)
|
||||
{
|
||||
SetRadius(radius);
|
||||
}
|
||||
|
||||
EllipseActor::~EllipseActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -271,11 +235,6 @@ namespace kiwano
|
|||
{
|
||||
}
|
||||
|
||||
PolygonActor::PolygonActor(Vector<Point> const& points)
|
||||
{
|
||||
SetVertices(points);
|
||||
}
|
||||
|
||||
PolygonActor::~PolygonActor()
|
||||
{
|
||||
}
|
||||
|
|
@ -296,56 +255,56 @@ namespace kiwano
|
|||
|
||||
|
||||
//-------------------------------------------------------
|
||||
// PathActor
|
||||
// PathShapeActor
|
||||
//-------------------------------------------------------
|
||||
|
||||
PathActor::PathActor()
|
||||
PathShapeActor::PathShapeActor()
|
||||
{
|
||||
}
|
||||
|
||||
PathActor::~PathActor()
|
||||
PathShapeActor::~PathShapeActor()
|
||||
{
|
||||
}
|
||||
|
||||
void PathActor::BeginPath(Point const& begin_pos)
|
||||
void PathShapeActor::BeginPath(Point const& begin_pos)
|
||||
{
|
||||
sink_.BeginPath(begin_pos);
|
||||
}
|
||||
|
||||
void PathActor::EndPath(bool closed)
|
||||
void PathShapeActor::EndPath(bool closed)
|
||||
{
|
||||
sink_.EndPath(closed);
|
||||
Geometry geo = sink_.GetGeometry();
|
||||
|
||||
if (geo)
|
||||
if (geo.IsValid())
|
||||
{
|
||||
SetGeometry(geo);
|
||||
}
|
||||
}
|
||||
|
||||
void PathActor::AddLine(Point const& point)
|
||||
void PathShapeActor::AddLine(Point const& point)
|
||||
{
|
||||
sink_.AddLine(point);
|
||||
}
|
||||
|
||||
void PathActor::AddLines(Vector<Point> const& points)
|
||||
void PathShapeActor::AddLines(Vector<Point> const& points)
|
||||
{
|
||||
sink_.AddLines(points);
|
||||
}
|
||||
|
||||
void PathActor::AddBezier(Point const& point1, Point const& point2, Point const& point3)
|
||||
void PathShapeActor::AddBezier(Point const& point1, Point const& point2, Point const& point3)
|
||||
{
|
||||
sink_.AddBezier(point1, point2, point3);
|
||||
}
|
||||
|
||||
void PathActor::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
|
||||
void PathShapeActor::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
|
||||
{
|
||||
sink_.AddArc(point, radius, rotation, clockwise, is_small);
|
||||
}
|
||||
|
||||
void PathActor::ClearPath()
|
||||
void PathShapeActor::ClearPath()
|
||||
{
|
||||
geo_.SetGeometry(nullptr);
|
||||
SetGeometry(Geometry());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,68 +20,113 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano/2d/Actor.h>
|
||||
#include <kiwano/renderer/Brush.h>
|
||||
#include <kiwano/renderer/Geometry.h>
|
||||
#include <kiwano/renderer/GeometrySink.h>
|
||||
#include <kiwano/renderer/StrokeStyle.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
// 二维图形角色
|
||||
KGE_DECLARE_SMART_PTR(ShapeActor);
|
||||
KGE_DECLARE_SMART_PTR(LineActor);
|
||||
KGE_DECLARE_SMART_PTR(RectActor);
|
||||
KGE_DECLARE_SMART_PTR(RoundRectActor);
|
||||
KGE_DECLARE_SMART_PTR(CircleActor);
|
||||
KGE_DECLARE_SMART_PTR(EllipseActor);
|
||||
KGE_DECLARE_SMART_PTR(PolygonActor);
|
||||
KGE_DECLARE_SMART_PTR(PathShapeActor);
|
||||
|
||||
/**
|
||||
* \addtogroup Actors
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 二维形状角色
|
||||
*/
|
||||
class KGE_API ShapeActor
|
||||
: public Actor
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 构造二维形状角色
|
||||
ShapeActor();
|
||||
|
||||
ShapeActor(
|
||||
Geometry const& geometry
|
||||
);
|
||||
|
||||
virtual ~ShapeActor();
|
||||
|
||||
// 获取填充颜色
|
||||
inline Color GetFillColor() const { return fill_color_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取填充画刷
|
||||
BrushPtr GetFillBrush() const;
|
||||
|
||||
// 获取线条颜色
|
||||
inline Color GetStrokeColor() const { return stroke_color_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取轮廓画刷
|
||||
BrushPtr GetStrokeBrush() const;
|
||||
|
||||
// 获取线条宽度
|
||||
inline float GetStrokeWidth() const { return stroke_width_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取线条宽度
|
||||
float GetStrokeWidth() const;
|
||||
|
||||
// 获取线条样式
|
||||
inline StrokeStyle SetStrokeStyle() const { return stroke_style_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取线条样式
|
||||
StrokeStyle SetStrokeStyle() const;
|
||||
|
||||
// 获取形状
|
||||
inline Geometry GetGeometry() const { return geo_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取形状
|
||||
Geometry GetGeometry() const;
|
||||
|
||||
// 获取边界
|
||||
/// \~chinese
|
||||
/// @brief 获取边界
|
||||
Rect GetBounds() const override;
|
||||
|
||||
// 获取外切包围盒
|
||||
/// \~chinese
|
||||
/// @brief 获取外切包围盒
|
||||
Rect GetBoundingBox() const override;
|
||||
|
||||
// 判断点是否在形状内
|
||||
/// \~chinese
|
||||
/// @brief 判断点是否在形状内
|
||||
bool ContainsPoint(const Point& point) const override;
|
||||
|
||||
// 设置填充颜色
|
||||
void SetFillColor(const Color& color);
|
||||
/// \~chinese
|
||||
/// @brief 设置填充颜色
|
||||
/// @param color 填充颜色
|
||||
void SetFillColor(Color const& color);
|
||||
|
||||
// 设置线条颜色
|
||||
void SetStrokeColor(const Color& color);
|
||||
/// \~chinese
|
||||
/// @brief 设置填充画刷
|
||||
/// @param[in] brush 填充画刷
|
||||
void SetFillBrush(BrushPtr brush);
|
||||
|
||||
// 设置线条宽度
|
||||
/// \~chinese
|
||||
/// @brief 设置轮廓颜色
|
||||
/// @param color 轮廓颜色
|
||||
void SetStrokeColor(Color const& color);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置轮廓画刷
|
||||
/// @param[in] brush 轮廓画刷
|
||||
void SetStrokeBrush(BrushPtr brush);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置线条宽度,默认为 1.0
|
||||
void SetStrokeWidth(float width);
|
||||
|
||||
// 设置线条样式
|
||||
/// \~chinese
|
||||
/// @brief 设置线条样式
|
||||
void SetStrokeStyle(StrokeStyle stroke_style);
|
||||
|
||||
// 设置形状
|
||||
/// \~chinese
|
||||
/// @brief 设置几何形状
|
||||
void SetGeometry(Geometry const& geometry);
|
||||
|
||||
void OnRender(RenderTarget* rt) override;
|
||||
|
||||
protected:
|
||||
Color fill_color_;
|
||||
Color stroke_color_;
|
||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
||||
|
||||
private:
|
||||
BrushPtr fill_brush_;
|
||||
BrushPtr stroke_brush_;
|
||||
float stroke_width_;
|
||||
StrokeStyle stroke_style_;
|
||||
Rect bounds_;
|
||||
|
|
@ -89,219 +134,269 @@ namespace kiwano
|
|||
};
|
||||
|
||||
|
||||
// 直线角色
|
||||
/// \~chinese
|
||||
/// @brief 线段图形角色
|
||||
class KGE_API LineActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
LineActor();
|
||||
|
||||
LineActor(
|
||||
Point const& begin,
|
||||
Point const& end
|
||||
);
|
||||
|
||||
virtual ~LineActor();
|
||||
|
||||
inline Point const& GetBeginPoint() const { return begin_; }
|
||||
|
||||
inline Point const& GetEndPoint() const { return end_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取线段起点
|
||||
Point const& GetBeginPoint() const;
|
||||
|
||||
inline void SetBeginPoint(Point const& begin)
|
||||
{
|
||||
SetLine(begin, end_);
|
||||
}
|
||||
/// \~chinese
|
||||
/// @brief 获取线段终点
|
||||
Point const& GetEndPoint() const;
|
||||
|
||||
inline void SetEndPoint(Point const& end)
|
||||
{
|
||||
SetLine(begin_, end);
|
||||
}
|
||||
/// \~chinese
|
||||
/// @brief 设置线段起点
|
||||
/// @param begin 线段起点
|
||||
void SetBeginPoint(Point const& begin);
|
||||
|
||||
void SetLine(
|
||||
Point const& begin,
|
||||
Point const& end
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置线段终点
|
||||
/// @param end 线段终点
|
||||
void SetEndPoint(Point const& end);
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 设置矩形大小
|
||||
/// @param begin 线段起点
|
||||
/// @param end 线段终点
|
||||
void SetLine(Point const& begin, Point const& end);
|
||||
|
||||
private:
|
||||
Point begin_;
|
||||
Point end_;
|
||||
};
|
||||
|
||||
|
||||
// 矩形角色
|
||||
/// \~chinese
|
||||
/// @brief 矩形角色
|
||||
class KGE_API RectActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
RectActor();
|
||||
|
||||
RectActor(
|
||||
Size const& size
|
||||
);
|
||||
|
||||
virtual ~RectActor();
|
||||
|
||||
inline Size const& GetRectSize() const { return rect_size_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取矩形大小
|
||||
Size const& GetRectSize() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置矩形大小
|
||||
/// @param size 矩形大小
|
||||
void SetRectSize(Size const& size);
|
||||
|
||||
protected:
|
||||
private:
|
||||
Size rect_size_;
|
||||
};
|
||||
|
||||
|
||||
// 圆角矩形角色
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 圆角矩形角色
|
||||
class KGE_API RoundRectActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
RoundRectActor();
|
||||
|
||||
RoundRectActor(
|
||||
Size const& size,
|
||||
Vec2 const& radius
|
||||
);
|
||||
|
||||
virtual ~RoundRectActor();
|
||||
|
||||
inline Vec2 GetRadius() const { return radius_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取圆角半径
|
||||
Vec2 GetRadius() const;
|
||||
|
||||
inline Size GetRectSize() const { return GetSize(); }
|
||||
/// \~chinese
|
||||
/// @brief 获取圆角矩形大小
|
||||
Size GetRectSize() const;
|
||||
|
||||
void SetRadius(
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置圆角半径
|
||||
/// @param radius 圆角半径
|
||||
void SetRadius(Vec2 const& radius);
|
||||
|
||||
void SetRectSize(
|
||||
Size const& size
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置圆角矩形大小
|
||||
/// @param size 圆角矩形大小
|
||||
void SetRectSize(Size const& size);
|
||||
|
||||
void SetRoundedRect(
|
||||
Size const& size,
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置圆角矩形
|
||||
/// @param size 圆角矩形大小
|
||||
/// @param radius 圆角半径
|
||||
void SetRoundedRect(Size const& size, Vec2 const& radius);
|
||||
|
||||
protected:
|
||||
private:
|
||||
Size rect_size_;
|
||||
Vec2 radius_;
|
||||
};
|
||||
|
||||
|
||||
// 圆形角色
|
||||
/// \~chinese
|
||||
/// @brief 圆形角色
|
||||
class KGE_API CircleActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
CircleActor();
|
||||
|
||||
CircleActor(
|
||||
float radius
|
||||
);
|
||||
|
||||
virtual ~CircleActor();
|
||||
|
||||
inline float GetRadius() const { return radius_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取圆形半径
|
||||
float GetRadius() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置圆形半径
|
||||
/// @param radius 圆形半径
|
||||
void SetRadius(float radius);
|
||||
|
||||
protected:
|
||||
private:
|
||||
float radius_;
|
||||
};
|
||||
|
||||
|
||||
// 椭圆角色
|
||||
/// \~chinese
|
||||
/// @brief 椭圆角色
|
||||
class KGE_API EllipseActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
EllipseActor();
|
||||
|
||||
EllipseActor(
|
||||
Vec2 const& radius
|
||||
);
|
||||
|
||||
virtual ~EllipseActor();
|
||||
|
||||
Vec2 GetRadius() const { return radius_; }
|
||||
/// \~chinese
|
||||
/// @brief 获取椭圆半径
|
||||
Vec2 GetRadius() const;
|
||||
|
||||
void SetRadius(
|
||||
Vec2 const& radius
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置椭圆半径
|
||||
/// @param radius 椭圆半径
|
||||
void SetRadius(Vec2 const& radius);
|
||||
|
||||
protected:
|
||||
private:
|
||||
Vec2 radius_;
|
||||
};
|
||||
|
||||
|
||||
// 多边形角色
|
||||
/// \~chinese
|
||||
/// @brief 多边形角色
|
||||
class KGE_API PolygonActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
PolygonActor();
|
||||
|
||||
PolygonActor(
|
||||
Vector<Point> const& points
|
||||
);
|
||||
|
||||
virtual ~PolygonActor();
|
||||
|
||||
void SetVertices(
|
||||
Vector<Point> const& points
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 设置多边形端点
|
||||
/// @param points 多边形端点集合
|
||||
void SetVertices(Vector<Point> const& points);
|
||||
};
|
||||
|
||||
|
||||
// 路径角色
|
||||
class KGE_API PathActor
|
||||
/// \~chinese
|
||||
/// @brief 路径图形角色
|
||||
class KGE_API PathShapeActor
|
||||
: public ShapeActor
|
||||
{
|
||||
public:
|
||||
PathActor();
|
||||
PathShapeActor();
|
||||
|
||||
virtual ~PathActor();
|
||||
virtual ~PathShapeActor();
|
||||
|
||||
// 开始添加路径
|
||||
void BeginPath(
|
||||
Point const& begin_pos = Point{} /* 起始点 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 开始添加路径
|
||||
/// @param begin_pos 起始点
|
||||
void BeginPath(Point const& begin_pos = Point());
|
||||
|
||||
// 结束路径
|
||||
void EndPath(
|
||||
bool closed = true /* 路径是否闭合 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 结束添加路径
|
||||
/// @param closed 路径是否闭合
|
||||
void EndPath(bool closed = true);
|
||||
|
||||
// 添加一条线段
|
||||
void AddLine(
|
||||
Point const& point /* 端点 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加一条线段
|
||||
/// @param point 线段端点
|
||||
void AddLine(Point const& point);
|
||||
|
||||
// 添加多条线段
|
||||
void AddLines(
|
||||
Vector<Point> const& points
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加多条线段
|
||||
/// @param points 线段端点集合
|
||||
void AddLines(Vector<Point> const& points);
|
||||
|
||||
// 添加一条三次方贝塞尔曲线
|
||||
void AddBezier(
|
||||
Point const& point1, /* 贝塞尔曲线的第一个控制点 */
|
||||
Point const& point2, /* 贝塞尔曲线的第二个控制点 */
|
||||
Point const& point3 /* 贝塞尔曲线的终点 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加一条三次方贝塞尔曲线
|
||||
/// @param point1 贝塞尔曲线的第一个控制点
|
||||
/// @param point2 贝塞尔曲线的第二个控制点
|
||||
/// @param point3 贝塞尔曲线的终点
|
||||
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
|
||||
|
||||
// 添加弧线
|
||||
void AddArc(
|
||||
Point const& point, /* 终点 */
|
||||
Size const& radius, /* 椭圆半径 */
|
||||
float rotation, /* 椭圆旋转角度 */
|
||||
bool clockwise = true, /* 顺时针 or 逆时针 */
|
||||
bool is_small = true /* 是否取小于 180° 的弧 */
|
||||
);
|
||||
/// \~chinese
|
||||
/// @brief 添加弧线
|
||||
/// @param point 椭圆圆心
|
||||
/// @param radius 椭圆半径
|
||||
/// @param rotation 椭圆旋转角度
|
||||
/// @param clockwise 顺时针 or 逆时针
|
||||
/// @param is_small 是否取小于 180° 的弧
|
||||
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
|
||||
|
||||
// 清除路径
|
||||
/// \~chinese
|
||||
/// @brief 清除路径
|
||||
void ClearPath();
|
||||
|
||||
protected:
|
||||
private:
|
||||
GeometrySink sink_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline void ShapeActor::SetStrokeColor(Color const& color)
|
||||
{
|
||||
if (!stroke_brush_)
|
||||
{
|
||||
stroke_brush_ = new Brush;
|
||||
}
|
||||
stroke_brush_->SetColor(color);
|
||||
}
|
||||
|
||||
inline void ShapeActor::SetFillColor(Color const& color)
|
||||
{
|
||||
if (!fill_brush_)
|
||||
{
|
||||
fill_brush_ = new Brush;
|
||||
}
|
||||
fill_brush_->SetColor(color);
|
||||
}
|
||||
|
||||
inline void ShapeActor::SetFillBrush(BrushPtr brush) { fill_brush_ = brush; }
|
||||
inline void ShapeActor::SetStrokeBrush(BrushPtr brush) { stroke_brush_ = brush; }
|
||||
inline BrushPtr ShapeActor::GetFillBrush() const { return fill_brush_; }
|
||||
inline BrushPtr ShapeActor::GetStrokeBrush() const { return stroke_brush_; }
|
||||
inline float ShapeActor::GetStrokeWidth() const { return stroke_width_; }
|
||||
inline StrokeStyle ShapeActor::SetStrokeStyle() const { return stroke_style_; }
|
||||
inline Geometry ShapeActor::GetGeometry() const { return geo_; }
|
||||
|
||||
inline Point const& LineActor::GetBeginPoint() const { return begin_; }
|
||||
inline Point const& LineActor::GetEndPoint() const { return end_; }
|
||||
inline void LineActor::SetBeginPoint(Point const& begin) { SetLine(begin, end_); }
|
||||
inline void LineActor::SetEndPoint(Point const& end) { SetLine(begin_, end); }
|
||||
|
||||
inline Size const& RectActor::GetRectSize() const { return rect_size_; }
|
||||
|
||||
inline Vec2 RoundRectActor::GetRadius() const { return radius_; }
|
||||
inline Size RoundRectActor::GetRectSize() const { return GetSize(); }
|
||||
|
||||
inline float CircleActor::GetRadius() const { return radius_; }
|
||||
|
||||
inline Vec2 EllipseActor::GetRadius() const { return radius_; }
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue