[deploy] Merge pull request #47 from KiwanoEngine/dev
Remove tinyxml2 & add pugixml
This commit is contained in:
commit
3da3cc6022
|
|
@ -0,0 +1,108 @@
|
||||||
|
# Clang-format version v9.0.0
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: Google
|
||||||
|
|
||||||
|
ColumnLimit: 120
|
||||||
|
|
||||||
|
##
|
||||||
|
## Indent Style
|
||||||
|
##
|
||||||
|
|
||||||
|
IndentWidth: 4
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
IndentCaseLabels: false
|
||||||
|
NamespaceIndentation: None
|
||||||
|
|
||||||
|
##
|
||||||
|
## Align Style
|
||||||
|
##
|
||||||
|
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
AlignConsecutiveDeclarations: true
|
||||||
|
AlignEscapedNewlinesLeft: true
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
PointerAlignment: Left
|
||||||
|
|
||||||
|
##
|
||||||
|
## SingleLine Style
|
||||||
|
##
|
||||||
|
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: true
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: true
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
BeforeCatch: true
|
||||||
|
BeforeElse: true
|
||||||
|
IndentBraces: true
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
CommentPragmas: "^ IWYU pragma:"
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
|
||||||
|
##
|
||||||
|
## Others
|
||||||
|
##
|
||||||
|
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakInheritanceList: BeforeComma
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
ForEachMacros: [foreach, Q_FOREACH, BOOST_FOREACH]
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: ".*"
|
||||||
|
Priority: 1
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ""
|
||||||
|
MacroBlockEnd: ""
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
|
@ -14,7 +14,7 @@ insert_final_newline = true
|
||||||
charset = gb2312
|
charset = gb2312
|
||||||
|
|
||||||
# 4 space indentation
|
# 4 space indentation
|
||||||
indent_style = tab
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
# Matches the exact files
|
# Matches the exact files
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|

|
||||||
|
|
||||||
|
# Kiwano 游戏引擎
|
||||||
|
|
||||||
|
[](https://ci.appveyor.com/project/Nomango/kiwano/branch/master)
|
||||||
|
[](https://github.com/Nomango/Kiwano/releases/latest)
|
||||||
|
[](https://github.com/Nomango/Kiwano/blob/master/LICENSE)
|
||||||
|
|
||||||
|
[English](./README.md) | 简体中文
|
||||||
|
|
||||||
|
## 介绍
|
||||||
|
|
||||||
|
Kiwano 是一个使用 C++ 开发的 2D 游戏引擎,目前仅支持 Windows 平台。
|
||||||
|
|
||||||
|
Kiwano-Core 是一个提供了一系列实用工具的游戏无关库,它的目的是简化 C++ 开发过程。
|
||||||
|
|
||||||
|
这个仓库仍处于开发过程中,我创建这个仓库用来学习游戏引擎知识和开发自己的小游戏。
|
||||||
|
|
||||||
|
你可以到 [Kiwano Demos](https://github.com/kiwanogame/KiwanoDemos) 仓库查看和学习如何使用 Kiwano 引擎实现小游戏。
|
||||||
|
|
||||||
|
欢迎您任何形式的贡献。
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
* 舞台和角色管理
|
||||||
|
* 舞台过渡动画
|
||||||
|
* 动作行为
|
||||||
|
* 按钮等简易UI元素
|
||||||
|
* 音频支持
|
||||||
|
* 网络通信支持
|
||||||
|
* 数据持久化
|
||||||
|
* 物理引擎 (基于 Box2D)
|
||||||
|
* GUI 引擎 (基于 ImGui)
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
### 开发环境
|
||||||
|
|
||||||
|
- Win8 或更高 (推荐 Win10)
|
||||||
|
- Visual Studio 2015 或更高
|
||||||
|
|
||||||
|
### 通过 NuGet 安装
|
||||||
|
|
||||||
|
1. 打开你的 Visual Studio 解决方案
|
||||||
|
2. 在解决方案资源管理器, 右击 `引用` 并选择 `管理 NuGet 程序包`
|
||||||
|
3. 选择 `浏览` 选项卡, 搜索 `kiwano`, 选中列表中的包然后点击 `安装`
|
||||||
|
4. 开始使用 Kiwano 进行开发吧!
|
||||||
|
|
||||||
|
### 通过源代码安装
|
||||||
|
|
||||||
|
1. 从 Github 仓库克隆或下载源代码
|
||||||
|
2. 打开你的 Visual Studio 解决方案, 在解决方案资源管理器中右键你的解决方案, 选择 `添加` => `现有项`
|
||||||
|
3. 选中源代码目录下 /projects 文件夹中所有的 `.vcxproj` 文件,并确认添加
|
||||||
|
4. 右键你的项目,打开 `属性`, 选中 C\C++ => 常规, 并将源代码文件夹下的 src 目录添加到 `附加包含目录` 中
|
||||||
|
5. 右键你的项目 `引用` 并选择 `添加引用`, 选中 `kiwano` 项目和其他你需要的项目
|
||||||
|
6. 开始使用 Kiwano 进行开发吧!
|
||||||
|
|
||||||
|
## 开发计划
|
||||||
|
|
||||||
|
* 跨平台支持
|
||||||
|
* 粒子系统
|
||||||
|
|
||||||
|
## 社交媒体
|
||||||
|
|
||||||
|
* 网站: [kiwanoengine.com](https://kiwanoengine.com)
|
||||||
|
* QQ群: 608406540
|
||||||
10
README.md
10
README.md
|
|
@ -6,6 +6,8 @@
|
||||||
[](https://github.com/Nomango/Kiwano/releases/latest)
|
[](https://github.com/Nomango/Kiwano/releases/latest)
|
||||||
[](https://github.com/Nomango/Kiwano/blob/master/LICENSE)
|
[](https://github.com/Nomango/Kiwano/blob/master/LICENSE)
|
||||||
|
|
||||||
|
English | [简体中文](./README-zh.md)
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
Kiwano is a open-source 2D C++ game engine, only support win32 platform.
|
Kiwano is a open-source 2D C++ game engine, only support win32 platform.
|
||||||
|
|
||||||
|
|
@ -20,12 +22,13 @@ More docs and examples will be added later.
|
||||||
## Features
|
## Features
|
||||||
* Scene management
|
* Scene management
|
||||||
* Transitions between scenes
|
* Transitions between scenes
|
||||||
* Actions behaviours
|
* Action behaviours
|
||||||
* Buttons and menus
|
* Buttons and menus
|
||||||
* Texture atlas support
|
* Texture atlas support
|
||||||
* Audio support
|
* Audio support
|
||||||
* Custom data storage
|
* Custom data storage
|
||||||
* Direct2D based
|
* Physical engine (based on Box2D)
|
||||||
|
* GUI system (based on ImGui)
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|
@ -51,8 +54,7 @@ More docs and examples will be added later.
|
||||||
6. Now you can build your own applications based on Kiwano source code !
|
6. Now you can build your own applications based on Kiwano source code !
|
||||||
|
|
||||||
## Next plan
|
## Next plan
|
||||||
* GUI system
|
* Cross-platform
|
||||||
* Physical engine
|
|
||||||
* Particle system
|
* Particle system
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
|
||||||
21
appveyor.yml
21
appveyor.yml
|
|
@ -19,7 +19,6 @@ pull_requests:
|
||||||
environment:
|
environment:
|
||||||
global:
|
global:
|
||||||
time_out_mins: 5
|
time_out_mins: 5
|
||||||
job_to_deploy: 6 # 3(images) * 1(platform) * 2(configuration)
|
|
||||||
flag_to_deploy: false
|
flag_to_deploy: false
|
||||||
appveyor_api_token:
|
appveyor_api_token:
|
||||||
secure: UJFCbRNHMOqQg3e3Kv/ZnaIqqwXAt+5HDldetaZsZ5E=
|
secure: UJFCbRNHMOqQg3e3Kv/ZnaIqqwXAt+5HDldetaZsZ5E=
|
||||||
|
|
@ -46,13 +45,12 @@ for:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
VS_PLATFORM_TOOLSET: v142
|
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
VS_PLATFORM_TOOLSET: v141
|
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
VS_PLATFORM_TOOLSET: v140
|
global:
|
||||||
|
job_to_deploy: 6 # 3(images) * 1(platform) * 2(configuration)
|
||||||
-
|
-
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
|
|
@ -62,7 +60,8 @@ for:
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
VS_PLATFORM_TOOLSET: v142
|
global:
|
||||||
|
job_to_deploy: 2 # 1(images) * 1(platform) * 2(configuration)
|
||||||
|
|
||||||
configuration:
|
configuration:
|
||||||
- Debug
|
- Debug
|
||||||
|
|
@ -90,9 +89,9 @@ after_build:
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: projects/output/**/*.lib
|
- path: projects/output/**/*.lib
|
||||||
name: $(appveyor_project_name)-v$(appveyor_build_version)-$(VS_PLATFORM_TOOLSET).$(platform).$(configuration)
|
name: PublishedLibraries
|
||||||
- path: projects/output/**/*.pdb
|
- path: projects/output/**/*.pdb
|
||||||
name: $(appveyor_project_name)-v$(appveyor_build_version)-$(VS_PLATFORM_TOOLSET).$(platform).$(configuration)
|
name: PublishedSymbols
|
||||||
|
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- ps: .\scripts\appveyor\coapp_make.ps1
|
- ps: .\scripts\appveyor\coapp_make.ps1
|
||||||
|
|
@ -100,9 +99,9 @@ before_deploy:
|
||||||
deploy:
|
deploy:
|
||||||
- provider: GitHub
|
- provider: GitHub
|
||||||
repository: KiwanoEngine/Kiwano
|
repository: KiwanoEngine/Kiwano
|
||||||
tag: v$(appveyor_build_version)
|
tag: v$(APPVEYOR_BUILD_VERSION)
|
||||||
release: v$(appveyor_build_version)
|
release: v$(APPVEYOR_BUILD_VERSION)
|
||||||
description: Kiwano-v$(appveyor_build_version) releases.
|
description: Kiwano-v$(APPVEYOR_BUILD_VERSION) releases.
|
||||||
auth_token:
|
auth_token:
|
||||||
secure: pDsK6i03d4qRjtrNXcbhLpAquso/muJWgDSWJHnxP7b6p54kXEvptB67J+1kJOhq
|
secure: pDsK6i03d4qRjtrNXcbhLpAquso/muJWgDSWJHnxP7b6p54kXEvptB67J+1kJOhq
|
||||||
artifact: /.*\.nupkg/
|
artifact: /.*\.nupkg/
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
<ClInclude Include="..\..\..\src\3rd-party\curl\typecheck-gcc.h">
|
<ClInclude Include="..\..\..\src\3rd-party\curl\typecheck-gcc.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\..\src\3rd-party\curl\tinyxml2.h" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Library Include="..\..\..\src\3rd-party\curl\libs\libcurl.lib">
|
<Library Include="..\..\..\src\3rd-party\curl\libs\libcurl.lib">
|
||||||
|
|
|
||||||
|
|
@ -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\tinyxml2\tinyxml2.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="..\..\..\src\3rd-party\tinyxml2\tinyxml2.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>{AB47E875-85E5-4105-A71E-88930EAAB910}</ProjectGuid>
|
|
||||||
<RootNamespace>libtinyxml2</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\tinyxml2\tinyxml2.cpp" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="..\..\..\src\3rd-party\tinyxml2\tinyxml2.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
|
|
@ -14,8 +14,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kiwano-physics", "kiwano-ph
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "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}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libimgui", "3rd-party\imgui\libimgui.vcxproj", "{7FA1E56D-62AC-47D1-97D1-40B302724198}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "3rd-party\curl\libcurl.vcxproj", "{A9ABACC7-75A1-46BA-8E48-4105346D9719}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "3rd-party\curl\libcurl.vcxproj", "{A9ABACC7-75A1-46BA-8E48-4105346D9719}"
|
||||||
|
|
@ -49,10 +47,6 @@ Global
|
||||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.Build.0 = 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.ActiveCfg = Release|Win32
|
||||||
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.Build.0 = Release|Win32
|
{DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.Build.0 = Release|Win32
|
||||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{AB47E875-85E5-4105-A71E-88930EAAB910}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
{7FA1E56D-62AC-47D1-97D1-40B302724198}.Debug|Win32.ActiveCfg = Debug|Win32
|
{7FA1E56D-62AC-47D1-97D1-40B302724198}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{7FA1E56D-62AC-47D1-97D1-40B302724198}.Debug|Win32.Build.0 = Debug|Win32
|
{7FA1E56D-62AC-47D1-97D1-40B302724198}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{7FA1E56D-62AC-47D1-97D1-40B302724198}.Release|Win32.ActiveCfg = Release|Win32
|
{7FA1E56D-62AC-47D1-97D1-40B302724198}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
|
@ -70,7 +64,6 @@ Global
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{AB47E875-85E5-4105-A71E-88930EAAB910} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
|
||||||
{7FA1E56D-62AC-47D1-97D1-40B302724198} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
{7FA1E56D-62AC-47D1-97D1-40B302724198} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||||
{A9ABACC7-75A1-46BA-8E48-4105346D9719} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
{A9ABACC7-75A1-46BA-8E48-4105346D9719} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||||
{0CBA9295-F14D-4966-A7C4-1DD68158176C} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
{0CBA9295-F14D-4966-A7C4-1DD68158176C} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,20 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\action\ActionWalk.h" />
|
<ClInclude Include="..\..\src\kiwano\2d\action\ActionWalk.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\action\ActionTween.h" />
|
<ClInclude Include="..\..\src\kiwano\2d\action\ActionTween.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\action\Animation.h" />
|
<ClInclude Include="..\..\src\kiwano\2d\action\Animation.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\2d\Button.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\Frame.h" />
|
<ClInclude Include="..\..\src\kiwano\2d\Frame.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\GifSprite.h" />
|
<ClInclude Include="..\..\src\kiwano\2d\GifSprite.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\common.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Common.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Director.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\event\Event.h" />
|
<ClInclude Include="..\..\src\kiwano\core\event\Event.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h" />
|
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h" />
|
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" />
|
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" />
|
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Keys.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Singleton.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Time.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\kiwano.h" />
|
<ClInclude Include="..\..\src\kiwano\kiwano.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\config.h" />
|
<ClInclude Include="..\..\src\kiwano\config.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\macros.h" />
|
<ClInclude Include="..\..\src\kiwano\macros.h" />
|
||||||
|
|
@ -36,7 +41,6 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Component.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Component.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\EventDispatcher.h" />
|
<ClInclude Include="..\..\src\kiwano\core\EventDispatcher.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\EventListener.h" />
|
<ClInclude Include="..\..\src\kiwano\core\EventListener.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\keys.h" />
|
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Logger.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Logger.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\ObjectBase.h" />
|
<ClInclude Include="..\..\src\kiwano\core\ObjectBase.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h" />
|
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h" />
|
||||||
|
|
@ -44,7 +48,6 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\SmartPtr.hpp" />
|
<ClInclude Include="..\..\src\kiwano\core\SmartPtr.hpp" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Timer.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Timer.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\TimerManager.h" />
|
<ClInclude Include="..\..\src\kiwano\core\TimerManager.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\time.h" />
|
|
||||||
<ClInclude Include="..\..\src\kiwano\math\constants.h" />
|
<ClInclude Include="..\..\src\kiwano\math\constants.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\math\ease.h" />
|
<ClInclude Include="..\..\src\kiwano\math\ease.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\math\math.h" />
|
<ClInclude Include="..\..\src\kiwano\math\math.h" />
|
||||||
|
|
@ -54,36 +57,33 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\math\scalar.h" />
|
<ClInclude Include="..\..\src\kiwano\math\scalar.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\math\Vec2.hpp" />
|
<ClInclude Include="..\..\src\kiwano\math\Vec2.hpp" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Application.h" />
|
<ClInclude Include="..\..\src\kiwano\platform\Application.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Director.h" />
|
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h" />
|
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Input.h" />
|
<ClInclude Include="..\..\src\kiwano\platform\Input.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
|
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h" />
|
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" />
|
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Window.h" />
|
<ClInclude Include="..\..\src\kiwano\platform\Window.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Brush.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Brush.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Color.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Color.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Font.h" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D2DDeviceResources.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Geometry.h" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\GifImage.h" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\StrokeStyle.h" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Texture.h" />
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\TextureCache.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Font.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\LayerArea.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Geometry.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Renderer.h" />
|
<ClInclude Include="..\..\src\kiwano\render\GeometrySink.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\RenderTarget.h" />
|
<ClInclude Include="..\..\src\kiwano\render\GifImage.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\TextLayout.h" />
|
<ClInclude Include="..\..\src\kiwano\render\LayerArea.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D2DDeviceResources.h" />
|
<ClInclude Include="..\..\src\kiwano\render\RenderContext.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D10DeviceResources.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Renderer.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.h" />
|
<ClInclude Include="..\..\src\kiwano\render\StrokeStyle.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3DDeviceResourcesBase.h" />
|
<ClInclude Include="..\..\src\kiwano\render\TextLayout.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.h" />
|
<ClInclude Include="..\..\src\kiwano\render\TextStyle.hpp" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h" />
|
<ClInclude Include="..\..\src\kiwano\render\Texture.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\TextRenderer.h" />
|
<ClInclude Include="..\..\src\kiwano\render\TextureCache.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\ui\Button.h" />
|
|
||||||
<ClInclude Include="..\..\src\kiwano\ui\Menu.h" />
|
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\ResourceCache.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\ResourceCache.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\utils\UserData.h" />
|
<ClInclude Include="..\..\src\kiwano\utils\UserData.h" />
|
||||||
|
|
@ -96,6 +96,7 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\action\ActionWalk.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\action\ActionWalk.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\action\ActionTween.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\action\ActionTween.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\action\Animation.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\action\Animation.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\kiwano\2d\Button.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\DebugActor.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\DebugActor.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Frame.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\Frame.cpp" />
|
||||||
|
|
@ -111,6 +112,7 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp" />
|
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\AsyncTask.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\AsyncTask.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\Component.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\Component.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\kiwano\core\Director.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\EventDispatcher.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\EventDispatcher.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\EventListener.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\EventListener.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp" />
|
||||||
|
|
@ -122,35 +124,34 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\kiwano\core\Time.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\TimerManager.cpp" />
|
<ClCompile Include="..\..\src\kiwano\core\TimerManager.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\core\time.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp" />
|
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp" />
|
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Input.cpp" />
|
<ClCompile Include="..\..\src\kiwano\platform\Input.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" />
|
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp" />
|
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\kiwano\platform\win32\WindowImpl.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp" />
|
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Brush.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Color.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Font.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\D2DDeviceResources.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Geometry.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\GifImage.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Texture.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextRenderer.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\TextureCache.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Font.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\LayerArea.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Geometry.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Renderer.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\GeometrySink.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\RenderTarget.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\GifImage.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\TextLayout.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\LayerArea.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\D2DDeviceResources.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\RenderContext.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\D3D10DeviceResources.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Renderer.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\StrokeStyle.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\TextLayout.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\TextRenderer.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\Texture.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp" />
|
<ClCompile Include="..\..\src\kiwano\render\TextureCache.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\ui\Menu.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\LocalStorage.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\LocalStorage.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\ResourceCache.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\ResourceCache.cpp" />
|
||||||
<ClCompile Include="..\..\src\kiwano\utils\UserData.cpp" />
|
<ClCompile Include="..\..\src\kiwano\utils\UserData.cpp" />
|
||||||
|
|
@ -165,11 +166,6 @@
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\3rd-party\tinyxml2\libtinyxml2.vcxproj">
|
|
||||||
<Project>{ab47e875-85e5-4105-a71e-88930eaab910}</Project>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{FF7F943D-A89C-4E6C-97CF-84F7D8FF8EDF}</ProjectGuid>
|
<ProjectGuid>{FF7F943D-A89C-4E6C-97CF-84F7D8FF8EDF}</ProjectGuid>
|
||||||
<RootNamespace>kiwano</RootNamespace>
|
<RootNamespace>kiwano</RootNamespace>
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,6 @@
|
||||||
<Filter Include="utils">
|
<Filter Include="utils">
|
||||||
<UniqueIdentifier>{68eac919-ee87-4030-a033-c251731928f5}</UniqueIdentifier>
|
<UniqueIdentifier>{68eac919-ee87-4030-a033-c251731928f5}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="ui">
|
|
||||||
<UniqueIdentifier>{07b6d541-4a1b-472a-aae0-daf9d082fe84}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="platform">
|
<Filter Include="platform">
|
||||||
<UniqueIdentifier>{c2654ccc-59f6-4c17-bb6b-99b07fc78702}</UniqueIdentifier>
|
<UniqueIdentifier>{c2654ccc-59f6-4c17-bb6b-99b07fc78702}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
|
@ -19,29 +16,23 @@
|
||||||
<Filter Include="core">
|
<Filter Include="core">
|
||||||
<UniqueIdentifier>{2e18d99a-e906-499a-9e29-4e0783202644}</UniqueIdentifier>
|
<UniqueIdentifier>{2e18d99a-e906-499a-9e29-4e0783202644}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="renderer">
|
|
||||||
<UniqueIdentifier>{7897afce-24cb-42b4-9443-56508e4ec89c}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="2d\action">
|
<Filter Include="2d\action">
|
||||||
<UniqueIdentifier>{9314f30d-5742-48b6-94e5-e3b4284106f6}</UniqueIdentifier>
|
<UniqueIdentifier>{9314f30d-5742-48b6-94e5-e3b4284106f6}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="renderer\win32">
|
|
||||||
<UniqueIdentifier>{30333461-e9bc-4709-84bd-ce6e0e1a3079}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="platform\win32">
|
<Filter Include="platform\win32">
|
||||||
<UniqueIdentifier>{e84dcf9a-e650-473e-8c9c-193804ab9e76}</UniqueIdentifier>
|
<UniqueIdentifier>{e84dcf9a-e650-473e-8c9c-193804ab9e76}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="core\event">
|
<Filter Include="core\event">
|
||||||
<UniqueIdentifier>{c629aedd-ffb9-4bc1-82c3-f50e77c82e77}</UniqueIdentifier>
|
<UniqueIdentifier>{c629aedd-ffb9-4bc1-82c3-f50e77c82e77}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="render">
|
||||||
|
<UniqueIdentifier>{adb44ca9-674a-4b77-993f-d65193d8ab06}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="render\DirectX">
|
||||||
|
<UniqueIdentifier>{fd281702-0006-46d2-8fd1-28c502464164}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\kiwano\ui\Button.h">
|
|
||||||
<Filter>ui</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\ui\Menu.h">
|
|
||||||
<Filter>ui</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\Canvas.h">
|
<ClInclude Include="..\..\src\kiwano\2d\Canvas.h">
|
||||||
<Filter>2d</Filter>
|
<Filter>2d</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -66,9 +57,6 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Resource.h">
|
<ClInclude Include="..\..\src\kiwano\core\Resource.h">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\core\time.h">
|
|
||||||
<Filter>core</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\math\Matrix.hpp">
|
<ClInclude Include="..\..\src\kiwano\math\Matrix.hpp">
|
||||||
<Filter>math</Filter>
|
<Filter>math</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -156,63 +144,9 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\ObjectBase.h">
|
<ClInclude Include="..\..\src\kiwano\core\ObjectBase.h">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Color.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Font.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Geometry.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\GifImage.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\LayerArea.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Renderer.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\TextLayout.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D2DDeviceResources.h">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D10DeviceResources.h">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.h">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3DDeviceResourcesBase.h">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.h">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\win32\TextRenderer.h">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\RenderTarget.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\Transform.h">
|
<ClInclude Include="..\..\src\kiwano\2d\Transform.h">
|
||||||
<Filter>2d</Filter>
|
<Filter>2d</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Texture.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\TextureCache.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\StrokeStyle.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\renderer\Brush.h">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\math\constants.h">
|
<ClInclude Include="..\..\src\kiwano\math\constants.h">
|
||||||
<Filter>math</Filter>
|
<Filter>math</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -234,36 +168,18 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h">
|
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h">
|
||||||
<Filter>platform</Filter>
|
<Filter>platform</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\core\keys.h">
|
|
||||||
<Filter>core</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Input.h">
|
<ClInclude Include="..\..\src\kiwano\platform\Input.h">
|
||||||
<Filter>platform</Filter>
|
<Filter>platform</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Window.h">
|
<ClInclude Include="..\..\src\kiwano\platform\Window.h">
|
||||||
<Filter>platform</Filter>
|
<Filter>platform</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\platform\Director.h">
|
|
||||||
<Filter>platform</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h">
|
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h">
|
||||||
<Filter>2d</Filter>
|
<Filter>2d</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\kiwano\core\common.h">
|
|
||||||
<Filter>core</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h">
|
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClInclude>
|
</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">
|
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp">
|
||||||
<Filter>platform\win32</Filter>
|
<Filter>platform\win32</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -288,14 +204,89 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h">
|
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h">
|
||||||
<Filter>core\event</Filter>
|
<Filter>core\event</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\2d\Button.h">
|
||||||
|
<Filter>2d</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Director.h">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Singleton.h">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Common.h">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Keys.h">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Time.h">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\Brush.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\Color.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\Font.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\Geometry.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\GeometrySink.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\GifImage.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\LayerArea.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\RenderContext.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\Renderer.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\StrokeStyle.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\TextLayout.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\TextStyle.hpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\Texture.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\TextureCache.h">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D2DDeviceResources.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp">
|
|
||||||
<Filter>ui</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\ui\Menu.cpp">
|
|
||||||
<Filter>ui</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
||||||
<Filter>2d</Filter>
|
<Filter>2d</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -317,9 +308,6 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp">
|
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\core\time.cpp">
|
|
||||||
<Filter>core</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp">
|
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp">
|
||||||
<Filter>platform</Filter>
|
<Filter>platform</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -383,57 +371,9 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp">
|
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Font.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Geometry.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\GifImage.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\LayerArea.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Renderer.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\TextLayout.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\D2DDeviceResources.cpp">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\D3D10DeviceResources.cpp">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.cpp">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.cpp">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\win32\TextRenderer.cpp">
|
|
||||||
<Filter>renderer\win32</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\RenderTarget.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp">
|
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp">
|
||||||
<Filter>2d</Filter>
|
<Filter>2d</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Texture.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\TextureCache.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\core\Component.cpp">
|
<ClCompile Include="..\..\src\kiwano\core\Component.cpp">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -455,18 +395,12 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp">
|
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp">
|
||||||
<Filter>platform</Filter>
|
<Filter>platform</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp">
|
|
||||||
<Filter>platform</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp">
|
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp">
|
||||||
<Filter>2d</Filter>
|
<Filter>2d</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp">
|
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp">
|
|
||||||
<Filter>renderer</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp">
|
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp">
|
||||||
<Filter>platform\win32</Filter>
|
<Filter>platform\win32</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -485,5 +419,71 @@
|
||||||
<ClCompile Include="..\..\src\kiwano\core\event\WindowEvent.cpp">
|
<ClCompile Include="..\..\src\kiwano\core\event\WindowEvent.cpp">
|
||||||
<Filter>core\event</Filter>
|
<Filter>core\event</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\2d\Button.cpp">
|
||||||
|
<Filter>2d</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\core\Director.cpp">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\platform\win32\WindowImpl.cpp">
|
||||||
|
<Filter>platform\win32</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\core\Time.cpp">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\Brush.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\Color.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\Font.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\Geometry.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\GeometrySink.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\GifImage.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\LayerArea.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\RenderContext.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\Renderer.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\StrokeStyle.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\TextLayout.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\Texture.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\TextureCache.cpp">
|
||||||
|
<Filter>render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\D2DDeviceResources.cpp">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.cpp">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.cpp">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.cpp">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextRenderer.cpp">
|
||||||
|
<Filter>render\DirectX</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# clang-format-all: a tool to run clang-format on an entire project
|
||||||
|
# Copyright (C) 2016 Evan Klitzke <evan@eklitzke.org>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $0 DIR..."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Variable that will hold the name of the clang-format command
|
||||||
|
FMT=""
|
||||||
|
|
||||||
|
# Some distros just call it clang-format. Others (e.g. Ubuntu) are insistent
|
||||||
|
# that the version number be part of the command. We prefer clang-format if
|
||||||
|
# that's present, otherwise we work backwards from highest version to lowest
|
||||||
|
# version.
|
||||||
|
for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do
|
||||||
|
if which "$clangfmt" &>/dev/null; then
|
||||||
|
FMT="$clangfmt"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if we found a working clang-format
|
||||||
|
if [ -z "$FMT" ]; then
|
||||||
|
echo "failed to find clang-format"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check all of the arguments first to make sure they're all directories
|
||||||
|
for dir in "$@"; do
|
||||||
|
if [ ! -d "${dir}" ]; then
|
||||||
|
echo "${dir} is not a directory"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Find a dominating file, starting from a given directory and going up.
|
||||||
|
find-dominating-file() {
|
||||||
|
if [ -r "$1"/"$2" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$1" = "/" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
find-dominating-file "$(realpath "$1"/..)" "$2"
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run clang-format -i on all of the things
|
||||||
|
for dir in "$@"; do
|
||||||
|
pushd "${dir}" &>/dev/null
|
||||||
|
if ! find-dominating-file . .clang-format; then
|
||||||
|
echo "Failed to find dominating .clang-format starting at $PWD"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
find . \
|
||||||
|
\( -name '*.c' \
|
||||||
|
-o -name '*.cc' \
|
||||||
|
-o -name '*.cpp' \
|
||||||
|
-o -name '*.h' \
|
||||||
|
-o -name '*.hh' \
|
||||||
|
-o -name '*.hpp' \) \
|
||||||
|
-exec "${FMT}" -i '{}' \;
|
||||||
|
popd &>/dev/null
|
||||||
|
done
|
||||||
|
|
@ -115,23 +115,23 @@ public:
|
||||||
|
|
||||||
virtual _Ret invoke(_Args... args) const override
|
virtual _Ret invoke(_Args... args) const override
|
||||||
{
|
{
|
||||||
return (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...);
|
return (ptr_->*func_)(::std::forward<_Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func)
|
static inline callable<_Ret, _Args...>* make(_Ty* ptr, _FuncType func)
|
||||||
{
|
{
|
||||||
return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func);
|
return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
proxy_mem_callable(void* ptr, _FuncType func)
|
proxy_mem_callable(_Ty* ptr, _FuncType func)
|
||||||
: ptr_(ptr)
|
: ptr_(ptr)
|
||||||
, func_(func)
|
, func_(func)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void* ptr_;
|
_Ty* ptr_;
|
||||||
_FuncType func_;
|
_FuncType func_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -144,23 +144,23 @@ public:
|
||||||
|
|
||||||
virtual _Ret invoke(_Args... args) const override
|
virtual _Ret invoke(_Args... args) const override
|
||||||
{
|
{
|
||||||
return (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...);
|
return (ptr_->*func_)(::std::forward<_Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func)
|
static inline callable<_Ret, _Args...>* make(_Ty* ptr, _FuncType func)
|
||||||
{
|
{
|
||||||
return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func);
|
return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
proxy_const_mem_callable(void* ptr, _FuncType func)
|
proxy_const_mem_callable(_Ty* ptr, _FuncType func)
|
||||||
: ptr_(ptr)
|
: ptr_(ptr)
|
||||||
, func_(func)
|
, func_(func)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void* ptr_;
|
_Ty* ptr_;
|
||||||
_FuncType func_;
|
_FuncType func_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,19 @@ template <typename _Ty, typename _PTy = typename std::pointer_traits<_Ty>::point
|
||||||
class intrusive_list_item
|
class intrusive_list_item
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using pointer_type = _PTy;
|
using pointer = _PTy;
|
||||||
using const_pointer_type = const _PTy;
|
|
||||||
|
|
||||||
intrusive_list_item() : prev_(nullptr), next_(nullptr) {}
|
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_; } }
|
intrusive_list_item(pointer rhs) : prev_(nullptr), next_(nullptr) { if (rhs) { prev_ = rhs->prev_; next_ = rhs->next_; } }
|
||||||
|
|
||||||
const_pointer_type prev_item() const { return prev_; }
|
const pointer prev_item() const { return prev_; }
|
||||||
pointer_type prev_item() { return prev_; }
|
pointer prev_item() { return prev_; }
|
||||||
const_pointer_type next_item() const { return next_; }
|
const pointer next_item() const { return next_; }
|
||||||
pointer_type next_item() { return next_; }
|
pointer next_item() { return next_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pointer_type prev_;
|
pointer prev_;
|
||||||
pointer_type next_;
|
pointer next_;
|
||||||
|
|
||||||
friend class intrusive_list<_Ty, _PTy>;
|
friend class intrusive_list<_Ty, _PTy>;
|
||||||
};
|
};
|
||||||
|
|
@ -39,23 +38,24 @@ template <typename _Ty, typename _PTy>
|
||||||
class intrusive_list
|
class intrusive_list
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using pointer_type = _PTy;
|
using value_type = typename std::pointer_traits<_PTy>::element_type;
|
||||||
using const_pointer_type = const _PTy;
|
using pointer = _PTy;
|
||||||
|
using reference = value_type&;
|
||||||
|
|
||||||
intrusive_list() : first_(), last_() {}
|
intrusive_list() : first_(), last_() {}
|
||||||
~intrusive_list() { clear(); }
|
~intrusive_list() { clear(); }
|
||||||
|
|
||||||
const_pointer_type first_item() const { return first_; }
|
const pointer first_item() const { return first_; }
|
||||||
pointer_type first_item() { return first_; }
|
pointer first_item() { return first_; }
|
||||||
const_pointer_type last_item() const { return last_; }
|
const pointer last_item() const { return last_; }
|
||||||
pointer_type last_item() { return last_; }
|
pointer last_item() { return last_; }
|
||||||
|
|
||||||
inline bool empty() const
|
inline bool empty() const
|
||||||
{
|
{
|
||||||
return first_ == nullptr;
|
return first_ == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(pointer_type child)
|
void push_back(pointer child)
|
||||||
{
|
{
|
||||||
if (child->prev_)
|
if (child->prev_)
|
||||||
child->prev_->next_ = child->next_;
|
child->prev_->next_ = child->next_;
|
||||||
|
|
@ -77,7 +77,7 @@ public:
|
||||||
last_ = child;
|
last_ = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_front(pointer_type child)
|
void push_front(pointer child)
|
||||||
{
|
{
|
||||||
if (child->prev_)
|
if (child->prev_)
|
||||||
child->prev_->next_ = child->next_;
|
child->prev_->next_ = child->next_;
|
||||||
|
|
@ -99,7 +99,7 @@ public:
|
||||||
first_ = child;
|
first_ = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_before(pointer_type child, pointer_type before)
|
void insert_before(pointer child, pointer before)
|
||||||
{
|
{
|
||||||
if (child->prev_)
|
if (child->prev_)
|
||||||
child->prev_->next_ = child->next_;
|
child->prev_->next_ = child->next_;
|
||||||
|
|
@ -116,7 +116,7 @@ public:
|
||||||
before->prev_ = child;
|
before->prev_ = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_after(pointer_type child, pointer_type after)
|
void insert_after(pointer child, pointer after)
|
||||||
{
|
{
|
||||||
if (child->prev_)
|
if (child->prev_)
|
||||||
child->prev_->next_ = child->next_;
|
child->prev_->next_ = child->next_;
|
||||||
|
|
@ -133,7 +133,7 @@ public:
|
||||||
after->next_ = child;
|
after->next_ = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(pointer_type child)
|
void remove(pointer child)
|
||||||
{
|
{
|
||||||
if (child->next_)
|
if (child->next_)
|
||||||
{
|
{
|
||||||
|
|
@ -159,10 +159,10 @@ public:
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
pointer_type p = first_;
|
pointer p = first_;
|
||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
pointer_type tmp = p;
|
pointer tmp = p;
|
||||||
p = p->next_;
|
p = p->next_;
|
||||||
if (tmp)
|
if (tmp)
|
||||||
{
|
{
|
||||||
|
|
@ -180,8 +180,8 @@ public:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
pointer_type p = first_;
|
pointer p = first_;
|
||||||
pointer_type tmp = p;
|
pointer tmp = p;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
tmp = p;
|
tmp = p;
|
||||||
|
|
@ -205,15 +205,19 @@ public:
|
||||||
struct iterator_impl
|
struct iterator_impl
|
||||||
{
|
{
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
using pointer_type = _PTy;
|
using value_type = typename std::pointer_traits<_PTy>::element_type;
|
||||||
using const_pointer_type = const _PTy;
|
using difference_type = ptrdiff_t;
|
||||||
|
using pointer = _PTy;
|
||||||
|
using reference = value_type&;
|
||||||
|
|
||||||
inline iterator_impl(pointer_type ptr = nullptr, bool is_end = false) : base_(ptr), is_end_(is_end) {}
|
inline iterator_impl(pointer 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 pointer base() const { OC_ASSERT(!is_end_); return const_cast<pointer&>(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 reference operator*() const { OC_ASSERT(base_ && !is_end_); return const_cast<reference>(*base_); }
|
||||||
|
inline pointer operator->() const { OC_ASSERT(base_ && !is_end_); return const_cast<pointer&>(base_); }
|
||||||
|
inline iterator_impl& operator++() { OC_ASSERT(base_ && !is_end_); pointer 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++(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--() { OC_ASSERT(base_); if (is_end_) is_end_ = false; else base_ = pointer(base_->prev_item()); return (*this); }
|
||||||
inline iterator_impl operator--(int) { iterator_impl old = (*this); --(*this); return old; }
|
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 base_ == other.base_ && is_end_ == other.is_end_; }
|
||||||
inline bool operator!=(iterator_impl const& other) const { return !(*this == other); }
|
inline bool operator!=(iterator_impl const& other) const { return !(*this == other); }
|
||||||
|
|
@ -221,11 +225,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_end_;
|
bool is_end_;
|
||||||
pointer_type base_;
|
pointer base_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using iterator = iterator_impl<pointer_type>;
|
using iterator = iterator_impl<pointer>;
|
||||||
using const_iterator = iterator_impl<const pointer_type>;
|
using const_iterator = iterator_impl<const pointer>;
|
||||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
|
@ -241,14 +245,14 @@ public:
|
||||||
inline reverse_iterator rend() { return reverse_iterator(begin()); }
|
inline reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||||
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||||
inline const_reverse_iterator crend() const { return rend(); }
|
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 pointer 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 const pointer 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 pointer 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(); }
|
inline const pointer back() const { if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pointer_type first_;
|
pointer first_;
|
||||||
pointer_type last_;
|
pointer last_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace oc
|
} // namespace oc
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* pugixml parser - version 1.10
|
||||||
|
* --------------------------------------------------------
|
||||||
|
* Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||||
|
* Report bugs and download new versions at https://pugixml.org/
|
||||||
|
*
|
||||||
|
* This library is distributed under the MIT License. See notice at the end
|
||||||
|
* of this file.
|
||||||
|
*
|
||||||
|
* This work is based on the pugxml parser, which is:
|
||||||
|
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HEADER_PUGICONFIG_HPP
|
||||||
|
#define HEADER_PUGICONFIG_HPP
|
||||||
|
|
||||||
|
// Uncomment this to enable wchar_t mode
|
||||||
|
#define PUGIXML_WCHAR_MODE
|
||||||
|
|
||||||
|
// Uncomment this to enable compact mode
|
||||||
|
// #define PUGIXML_COMPACT
|
||||||
|
|
||||||
|
// Uncomment this to disable XPath
|
||||||
|
// #define PUGIXML_NO_XPATH
|
||||||
|
|
||||||
|
// Uncomment this to disable STL
|
||||||
|
// #define PUGIXML_NO_STL
|
||||||
|
|
||||||
|
// Uncomment this to disable exceptions
|
||||||
|
#define PUGIXML_NO_EXCEPTIONS
|
||||||
|
|
||||||
|
// Set this to control attributes for public classes/functions, i.e.:
|
||||||
|
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||||
|
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||||
|
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||||
|
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||||
|
|
||||||
|
// Tune these constants to adjust memory-related behavior
|
||||||
|
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||||
|
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||||
|
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
// Uncomment this to switch to header-only version
|
||||||
|
#define PUGIXML_HEADER_ONLY
|
||||||
|
|
||||||
|
// Uncomment this to enable long long support
|
||||||
|
// #define PUGIXML_HAS_LONG_LONG
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2006-2019 Arseny Kapoulkine
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,18 +0,0 @@
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any
|
|
||||||
damages arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any
|
|
||||||
purpose, including commercial applications, and to alter it and
|
|
||||||
redistribute it freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must
|
|
||||||
not claim that you wrote the original software. If you use this
|
|
||||||
software in a product, an acknowledgment in the product documentation
|
|
||||||
would be appreciated but is not required.
|
|
||||||
|
|
||||||
2. Altered source versions must be plainly marked as such, and
|
|
||||||
must not be misrepresented as being the original software.
|
|
||||||
|
|
||||||
3. This notice may not be removed or altered from any source
|
|
||||||
distribution.
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -18,108 +18,106 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/platform/win32/helper.h> // win32::ThrowIfFailed
|
|
||||||
#include <kiwano/core/Logger.h>
|
|
||||||
#include <kiwano-audio/libraries.h>
|
|
||||||
#include <kiwano-audio/AudioEngine.h>
|
#include <kiwano-audio/AudioEngine.h>
|
||||||
|
#include <kiwano-audio/libraries.h>
|
||||||
|
#include <kiwano/core/Logger.h>
|
||||||
|
#include <kiwano/platform/win32/helper.h> // win32::ThrowIfFailed
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
AudioEngine::AudioEngine()
|
AudioEngine::AudioEngine()
|
||||||
: x_audio2_(nullptr)
|
: x_audio2_(nullptr)
|
||||||
, mastering_voice_(nullptr)
|
, mastering_voice_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
AudioEngine::~AudioEngine()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioEngine::SetupComponent()
|
|
||||||
{
|
|
||||||
KGE_SYS_LOG(L"Creating audio resources");
|
|
||||||
|
|
||||||
HRESULT hr = dlls::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = dlls::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
|
|
||||||
}
|
|
||||||
|
|
||||||
win32::ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioEngine::DestroyComponent()
|
|
||||||
{
|
|
||||||
KGE_SYS_LOG(L"Destroying audio resources");
|
|
||||||
|
|
||||||
if (mastering_voice_)
|
|
||||||
{
|
|
||||||
mastering_voice_->DestroyVoice();
|
|
||||||
mastering_voice_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x_audio2_)
|
|
||||||
{
|
|
||||||
x_audio2_->Release();
|
|
||||||
x_audio2_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
dlls::MediaFoundation::Get().MFShutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioEngine::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
if (buffer.format == nullptr)
|
|
||||||
hr = E_INVALIDARG;
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
win32::WarnIfFailed(hr);
|
|
||||||
return SUCCEEDED(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioEngine::Open()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
|
||||||
|
|
||||||
if (x_audio2_)
|
|
||||||
x_audio2_->StartEngine();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioEngine::Close()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
|
||||||
|
|
||||||
if (x_audio2_)
|
|
||||||
x_audio2_->StopEngine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioEngine::~AudioEngine() {}
|
||||||
|
|
||||||
|
void AudioEngine::SetupComponent()
|
||||||
|
{
|
||||||
|
KGE_SYS_LOG(L"Creating audio resources");
|
||||||
|
|
||||||
|
HRESULT hr = dlls::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = dlls::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
|
||||||
|
}
|
||||||
|
|
||||||
|
win32::ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEngine::DestroyComponent()
|
||||||
|
{
|
||||||
|
KGE_SYS_LOG(L"Destroying audio resources");
|
||||||
|
|
||||||
|
if (mastering_voice_)
|
||||||
|
{
|
||||||
|
mastering_voice_->DestroyVoice();
|
||||||
|
mastering_voice_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x_audio2_)
|
||||||
|
{
|
||||||
|
x_audio2_->Release();
|
||||||
|
x_audio2_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlls::MediaFoundation::Get().MFShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioEngine::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
||||||
|
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
if (buffer.format == nullptr)
|
||||||
|
hr = E_INVALIDARG;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
win32::WarnIfFailed(hr);
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEngine::Open()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
||||||
|
|
||||||
|
if (x_audio2_)
|
||||||
|
x_audio2_->StartEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEngine::Close()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!");
|
||||||
|
|
||||||
|
if (x_audio2_)
|
||||||
|
x_audio2_->StopEngine();
|
||||||
|
}
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,64 +19,66 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/common.h>
|
|
||||||
#include <kiwano/core/Component.h>
|
|
||||||
#include <kiwano-audio/Transcoder.h>
|
|
||||||
#include <kiwano-audio/Sound.h>
|
#include <kiwano-audio/Sound.h>
|
||||||
|
#include <kiwano-audio/Transcoder.h>
|
||||||
|
#include <kiwano/core/Common.h>
|
||||||
|
#include <kiwano/core/Component.h>
|
||||||
#include <xaudio2.h>
|
#include <xaudio2.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* \defgroup Audio 音频引擎
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Audio
|
* \~chinese
|
||||||
* @{
|
* \defgroup Audio 音频引擎
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \addtogroup Audio
|
||||||
* @brief 音频引擎
|
* @{
|
||||||
*/
|
*/
|
||||||
class KGE_API AudioEngine
|
|
||||||
: public Singleton<AudioEngine>
|
|
||||||
, public ComponentBase
|
|
||||||
{
|
|
||||||
friend Singleton<AudioEngine>;
|
|
||||||
|
|
||||||
public:
|
/**
|
||||||
/// \~chinese
|
* \~chinese
|
||||||
/// @brief 开启音频设备
|
* @brief 音频引擎
|
||||||
void Open();
|
*/
|
||||||
|
class KGE_API AudioEngine
|
||||||
|
: public Singleton<AudioEngine>
|
||||||
|
, public ComponentBase
|
||||||
|
{
|
||||||
|
friend Singleton<AudioEngine>;
|
||||||
|
|
||||||
/// \~chinese
|
public:
|
||||||
/// @brief 关闭音频设备
|
/// \~chinese
|
||||||
void Close();
|
/// @brief 开启音频设备
|
||||||
|
void Open();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 从解码器数据缓冲中创建音频对象
|
/// @brief 关闭音频设备
|
||||||
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
|
void Close();
|
||||||
|
|
||||||
public:
|
/// \~chinese
|
||||||
void SetupComponent() override;
|
/// @brief 从解码器数据缓冲中创建音频对象
|
||||||
|
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
|
||||||
|
|
||||||
void DestroyComponent() override;
|
public:
|
||||||
|
void SetupComponent() override;
|
||||||
|
|
||||||
private:
|
void DestroyComponent() override;
|
||||||
AudioEngine();
|
|
||||||
|
|
||||||
~AudioEngine();
|
private:
|
||||||
|
AudioEngine();
|
||||||
|
|
||||||
private:
|
~AudioEngine();
|
||||||
IXAudio2* x_audio2_;
|
|
||||||
IXAudio2MasteringVoice* mastering_voice_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
private:
|
||||||
}
|
IXAudio2* x_audio2_;
|
||||||
}
|
IXAudio2MasteringVoice* mastering_voice_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,210 +18,210 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <kiwano-audio/AudioEngine.h>
|
||||||
|
#include <kiwano-audio/Sound.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
#include <kiwano/platform/FileSystem.h>
|
#include <kiwano/platform/FileSystem.h>
|
||||||
#include <kiwano-audio/Sound.h>
|
|
||||||
#include <kiwano-audio/AudioEngine.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
|
|
||||||
Sound::Sound()
|
Sound::Sound()
|
||||||
: opened_(false)
|
: opened_(false)
|
||||||
, playing_(false)
|
, playing_(false)
|
||||||
, voice_(nullptr)
|
, voice_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Sound::~Sound()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sound::Load(String const& file_path)
|
|
||||||
{
|
|
||||||
if (!FileSystem::instance().IsFileExists(file_path))
|
|
||||||
{
|
|
||||||
KGE_WARN(L"Media file '%s' not found", file_path.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opened_)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
String full_path = FileSystem::instance().GetFullPathForFile(file_path);
|
|
||||||
|
|
||||||
HRESULT hr = transcoder_.LoadMediaFile(full_path);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"Load media file failed with HRESULT of %08X", hr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer()))
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
opened_ = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sound::Load(Resource const& res)
|
|
||||||
{
|
|
||||||
if (opened_)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT hr = transcoder_.LoadMediaResource(res);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"Load media resource failed with HRESULT of %08X", hr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer()))
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
opened_ = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sound::IsValid() const
|
|
||||||
{
|
|
||||||
return voice_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::Play(int loop_count)
|
|
||||||
{
|
|
||||||
if (!opened_)
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"Sound must be opened first!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
// if sound stream is not empty, stop() will clear it
|
|
||||||
XAUDIO2_VOICE_STATE state;
|
|
||||||
voice_->GetState(&state);
|
|
||||||
if (state.BuffersQueued)
|
|
||||||
Stop();
|
|
||||||
|
|
||||||
// clamp loop count
|
|
||||||
loop_count = (loop_count < 0) ? XAUDIO2_LOOP_INFINITE : std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
|
|
||||||
|
|
||||||
auto wave_buffer = transcoder_.GetBuffer();
|
|
||||||
|
|
||||||
XAUDIO2_BUFFER buffer = { 0 };
|
|
||||||
buffer.pAudioData = wave_buffer.data;
|
|
||||||
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
|
||||||
buffer.AudioBytes = wave_buffer.size;
|
|
||||||
buffer.LoopCount = static_cast<uint32_t>(loop_count);
|
|
||||||
|
|
||||||
HRESULT hr = voice_->SubmitSourceBuffer(&buffer);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = voice_->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"Submitting source buffer failed with HRESULT of %08X", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
playing_ = SUCCEEDED(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::Pause()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
if (SUCCEEDED(voice_->Stop()))
|
|
||||||
playing_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::Resume()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
if (SUCCEEDED(voice_->Start()))
|
|
||||||
playing_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::Stop()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
HRESULT hr = voice_->Stop();
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
hr = voice_->ExitLoop();
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
hr = voice_->FlushSourceBuffers();
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
playing_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::Close()
|
|
||||||
{
|
|
||||||
if (voice_)
|
|
||||||
{
|
|
||||||
voice_->Stop();
|
|
||||||
voice_->FlushSourceBuffers();
|
|
||||||
voice_->DestroyVoice();
|
|
||||||
voice_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
transcoder_.ClearBuffer();
|
|
||||||
|
|
||||||
opened_ = false;
|
|
||||||
playing_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sound::IsPlaying() const
|
|
||||||
{
|
|
||||||
if (opened_)
|
|
||||||
{
|
|
||||||
if (!voice_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
XAUDIO2_VOICE_STATE state;
|
|
||||||
voice_->GetState(&state);
|
|
||||||
uint32_t buffers_queued = state.BuffersQueued;
|
|
||||||
|
|
||||||
if (buffers_queued && playing_)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Sound::GetVolume() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
float volume = 0.0f;
|
|
||||||
voice_->GetVolume(&volume);
|
|
||||||
return volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sound::SetVolume(float volume)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
volume = std::min(std::max(volume, -224.f), 224.f);
|
|
||||||
voice_->SetVolume(volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sound::~Sound()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound::Load(String const& file_path)
|
||||||
|
{
|
||||||
|
if (!FileSystem::Instance().IsFileExists(file_path))
|
||||||
|
{
|
||||||
|
KGE_WARN(L"Media file '%s' not found", file_path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opened_)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
|
||||||
|
|
||||||
|
HRESULT hr = transcoder_.LoadMediaFile(full_path);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"Load media file failed with HRESULT of %08X", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer()))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
opened_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound::Load(Resource const& res)
|
||||||
|
{
|
||||||
|
if (opened_)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hr = transcoder_.LoadMediaResource(res);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"Load media resource failed with HRESULT of %08X", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer()))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
opened_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound::IsValid() const
|
||||||
|
{
|
||||||
|
return voice_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::Play(int loop_count)
|
||||||
|
{
|
||||||
|
if (!opened_)
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"Sound must be opened first!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
|
// if sound stream is not empty, stop() will clear it
|
||||||
|
XAUDIO2_VOICE_STATE state;
|
||||||
|
voice_->GetState(&state);
|
||||||
|
if (state.BuffersQueued)
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
// clamp loop count
|
||||||
|
loop_count = (loop_count < 0) ? XAUDIO2_LOOP_INFINITE : std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
|
||||||
|
|
||||||
|
auto wave_buffer = transcoder_.GetBuffer();
|
||||||
|
|
||||||
|
XAUDIO2_BUFFER buffer = { 0 };
|
||||||
|
buffer.pAudioData = wave_buffer.data;
|
||||||
|
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
||||||
|
buffer.AudioBytes = wave_buffer.size;
|
||||||
|
buffer.LoopCount = static_cast<uint32_t>(loop_count);
|
||||||
|
|
||||||
|
HRESULT hr = voice_->SubmitSourceBuffer(&buffer);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = voice_->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"Submitting source buffer failed with HRESULT of %08X", hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
playing_ = SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::Pause()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
|
if (SUCCEEDED(voice_->Stop()))
|
||||||
|
playing_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::Resume()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
|
if (SUCCEEDED(voice_->Start()))
|
||||||
|
playing_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::Stop()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
|
HRESULT hr = voice_->Stop();
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = voice_->ExitLoop();
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = voice_->FlushSourceBuffers();
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
playing_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::Close()
|
||||||
|
{
|
||||||
|
if (voice_)
|
||||||
|
{
|
||||||
|
voice_->Stop();
|
||||||
|
voice_->FlushSourceBuffers();
|
||||||
|
voice_->DestroyVoice();
|
||||||
|
voice_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
transcoder_.ClearBuffer();
|
||||||
|
|
||||||
|
opened_ = false;
|
||||||
|
playing_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound::IsPlaying() const
|
||||||
|
{
|
||||||
|
if (opened_)
|
||||||
|
{
|
||||||
|
if (!voice_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
XAUDIO2_VOICE_STATE state;
|
||||||
|
voice_->GetState(&state);
|
||||||
|
uint32_t buffers_queued = state.BuffersQueued;
|
||||||
|
|
||||||
|
if (buffers_queued && playing_)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Sound::GetVolume() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
|
float volume = 0.0f;
|
||||||
|
voice_->GetVolume(&volume);
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::SetVolume(float volume)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
|
volume = std::min(std::max(volume, -224.f), 224.f);
|
||||||
|
voice_->SetVolume(volume);
|
||||||
|
}
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,110 +19,108 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <kiwano-audio/Transcoder.h>
|
||||||
#include <kiwano/core/ObjectBase.h>
|
#include <kiwano/core/ObjectBase.h>
|
||||||
#include <kiwano/core/Resource.h>
|
#include <kiwano/core/Resource.h>
|
||||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||||
#include <kiwano-audio/Transcoder.h>
|
|
||||||
#include <xaudio2.h>
|
#include <xaudio2.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
class AudioEngine;
|
class AudioEngine;
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(Sound);
|
KGE_DECLARE_SMART_PTR(Sound);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Audio
|
* \addtogroup Audio
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频
|
* @brief 音频
|
||||||
*/
|
*/
|
||||||
class KGE_API Sound
|
class KGE_API Sound : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
friend class AudioEngine;
|
||||||
friend class AudioEngine;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Sound();
|
Sound();
|
||||||
|
|
||||||
virtual ~Sound();
|
virtual ~Sound();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 打开本地音频文件
|
/// @brief 打开本地音频文件
|
||||||
/// @param res 本地音频文件路径
|
/// @param res 本地音频文件路径
|
||||||
bool Load(String const& file_path);
|
bool Load(String const& file_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 打开音频资源
|
/// @brief 打开音频资源
|
||||||
/// @param res 音频资源
|
/// @param res 音频资源
|
||||||
bool Load(Resource const& res);
|
bool Load(Resource const& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否有效
|
/// @brief 是否有效
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 播放
|
/// @brief 播放
|
||||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||||
void Play(int loop_count = 0);
|
void Play(int loop_count = 0);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 暂停
|
/// @brief 暂停
|
||||||
void Pause();
|
void Pause();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 继续
|
/// @brief 继续
|
||||||
void Resume();
|
void Resume();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 停止
|
/// @brief 停止
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 关闭并销毁资源
|
/// @brief 关闭并销毁资源
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否正在播放
|
/// @brief 是否正在播放
|
||||||
bool IsPlaying() const;
|
bool IsPlaying() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取音量
|
/// @brief 获取音量
|
||||||
float GetVolume() const;
|
float GetVolume() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置音量
|
/// @brief 设置音量
|
||||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||||
void SetVolume(float volume);
|
void SetVolume(float volume);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IXAudio2SourceVoice* GetXAudio2Voice() const;
|
IXAudio2SourceVoice* GetXAudio2Voice() const;
|
||||||
|
|
||||||
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
|
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool opened_;
|
bool opened_;
|
||||||
bool playing_;
|
bool playing_;
|
||||||
Transcoder transcoder_;
|
Transcoder transcoder_;
|
||||||
IXAudio2SourceVoice* voice_;
|
IXAudio2SourceVoice* voice_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
|
||||||
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
|
{
|
||||||
{
|
return voice_;
|
||||||
return voice_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
|
|
||||||
{
|
|
||||||
voice_ = voice;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
|
||||||
|
{
|
||||||
|
voice_ = voice;
|
||||||
|
}
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -22,135 +22,135 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
SoundPlayer::SoundPlayer()
|
SoundPlayer::SoundPlayer()
|
||||||
: volume_(1.f)
|
: volume_(1.f)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
SoundPlayer::~SoundPlayer()
|
|
||||||
{
|
|
||||||
ClearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SoundPlayer::Load(String const& file_path)
|
|
||||||
{
|
|
||||||
int hash_code = static_cast<int>(file_path.hash());
|
|
||||||
if (sound_cache_.end() != sound_cache_.find(hash_code))
|
|
||||||
return hash_code;
|
|
||||||
|
|
||||||
SoundPtr sound = new (std::nothrow) Sound;
|
|
||||||
|
|
||||||
if (sound)
|
|
||||||
{
|
|
||||||
if (sound->Load(file_path))
|
|
||||||
{
|
|
||||||
sound->SetVolume(volume_);
|
|
||||||
sound_cache_.insert(std::make_pair(hash_code, sound));
|
|
||||||
return hash_code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SoundPlayer::Load(Resource const& res)
|
|
||||||
{
|
|
||||||
size_t hash_code = static_cast<size_t>(res.GetId());
|
|
||||||
if (sound_cache_.end() != sound_cache_.find(hash_code))
|
|
||||||
return hash_code;
|
|
||||||
|
|
||||||
SoundPtr sound = new (std::nothrow) Sound;
|
|
||||||
|
|
||||||
if (sound)
|
|
||||||
{
|
|
||||||
if (sound->Load(res))
|
|
||||||
{
|
|
||||||
sound->SetVolume(volume_);
|
|
||||||
sound_cache_.insert(std::make_pair(hash_code, sound));
|
|
||||||
return hash_code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::Play(size_t id, int loop_count)
|
|
||||||
{
|
|
||||||
auto iter = sound_cache_.find(id);
|
|
||||||
if (sound_cache_.end() != iter)
|
|
||||||
iter->second->Play(loop_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::Pause(size_t id)
|
|
||||||
{
|
|
||||||
auto iter = sound_cache_.find(id);
|
|
||||||
if (sound_cache_.end() != iter)
|
|
||||||
iter->second->Pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::Resume(size_t id)
|
|
||||||
{
|
|
||||||
auto iter = sound_cache_.find(id);
|
|
||||||
if (sound_cache_.end() != iter)
|
|
||||||
iter->second->Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::Stop(size_t id)
|
|
||||||
{
|
|
||||||
auto iter = sound_cache_.find(id);
|
|
||||||
if (sound_cache_.end() != iter)
|
|
||||||
iter->second->Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SoundPlayer::IsPlaying(size_t id)
|
|
||||||
{
|
|
||||||
auto iter = sound_cache_.find(id);
|
|
||||||
if (sound_cache_.end() != iter)
|
|
||||||
return iter->second->IsPlaying();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float SoundPlayer::GetVolume() const
|
|
||||||
{
|
|
||||||
return volume_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::SetVolume(float volume)
|
|
||||||
{
|
|
||||||
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
|
||||||
for (auto& pair : sound_cache_)
|
|
||||||
{
|
|
||||||
pair.second->SetVolume(volume_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::PauseAll()
|
|
||||||
{
|
|
||||||
for (auto& pair : sound_cache_)
|
|
||||||
{
|
|
||||||
pair.second->Pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::ResumeAll()
|
|
||||||
{
|
|
||||||
for (auto& pair : sound_cache_)
|
|
||||||
{
|
|
||||||
pair.second->Resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::StopAll()
|
|
||||||
{
|
|
||||||
for (auto& pair : sound_cache_)
|
|
||||||
{
|
|
||||||
pair.second->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundPlayer::ClearCache()
|
|
||||||
{
|
|
||||||
sound_cache_.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SoundPlayer::~SoundPlayer()
|
||||||
|
{
|
||||||
|
ClearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SoundPlayer::Load(String const& file_path)
|
||||||
|
{
|
||||||
|
int hash_code = static_cast<int>(file_path.hash());
|
||||||
|
if (sound_cache_.end() != sound_cache_.find(hash_code))
|
||||||
|
return hash_code;
|
||||||
|
|
||||||
|
SoundPtr sound = new (std::nothrow) Sound;
|
||||||
|
|
||||||
|
if (sound)
|
||||||
|
{
|
||||||
|
if (sound->Load(file_path))
|
||||||
|
{
|
||||||
|
sound->SetVolume(volume_);
|
||||||
|
sound_cache_.insert(std::make_pair(hash_code, sound));
|
||||||
|
return hash_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SoundPlayer::Load(Resource const& res)
|
||||||
|
{
|
||||||
|
size_t hash_code = static_cast<size_t>(res.GetId());
|
||||||
|
if (sound_cache_.end() != sound_cache_.find(hash_code))
|
||||||
|
return hash_code;
|
||||||
|
|
||||||
|
SoundPtr sound = new (std::nothrow) Sound;
|
||||||
|
|
||||||
|
if (sound)
|
||||||
|
{
|
||||||
|
if (sound->Load(res))
|
||||||
|
{
|
||||||
|
sound->SetVolume(volume_);
|
||||||
|
sound_cache_.insert(std::make_pair(hash_code, sound));
|
||||||
|
return hash_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::Play(size_t id, int loop_count)
|
||||||
|
{
|
||||||
|
auto iter = sound_cache_.find(id);
|
||||||
|
if (sound_cache_.end() != iter)
|
||||||
|
iter->second->Play(loop_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::Pause(size_t id)
|
||||||
|
{
|
||||||
|
auto iter = sound_cache_.find(id);
|
||||||
|
if (sound_cache_.end() != iter)
|
||||||
|
iter->second->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::Resume(size_t id)
|
||||||
|
{
|
||||||
|
auto iter = sound_cache_.find(id);
|
||||||
|
if (sound_cache_.end() != iter)
|
||||||
|
iter->second->Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::Stop(size_t id)
|
||||||
|
{
|
||||||
|
auto iter = sound_cache_.find(id);
|
||||||
|
if (sound_cache_.end() != iter)
|
||||||
|
iter->second->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SoundPlayer::IsPlaying(size_t id)
|
||||||
|
{
|
||||||
|
auto iter = sound_cache_.find(id);
|
||||||
|
if (sound_cache_.end() != iter)
|
||||||
|
return iter->second->IsPlaying();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SoundPlayer::GetVolume() const
|
||||||
|
{
|
||||||
|
return volume_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::SetVolume(float volume)
|
||||||
|
{
|
||||||
|
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
||||||
|
for (auto& pair : sound_cache_)
|
||||||
|
{
|
||||||
|
pair.second->SetVolume(volume_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::PauseAll()
|
||||||
|
{
|
||||||
|
for (auto& pair : sound_cache_)
|
||||||
|
{
|
||||||
|
pair.second->Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::ResumeAll()
|
||||||
|
{
|
||||||
|
for (auto& pair : sound_cache_)
|
||||||
|
{
|
||||||
|
pair.second->Resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::StopAll()
|
||||||
|
{
|
||||||
|
for (auto& pair : sound_cache_)
|
||||||
|
{
|
||||||
|
pair.second->Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundPlayer::ClearCache()
|
||||||
|
{
|
||||||
|
sound_cache_.clear();
|
||||||
|
}
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,102 +19,101 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/ObjectBase.h>
|
|
||||||
#include <kiwano-audio/Sound.h>
|
#include <kiwano-audio/Sound.h>
|
||||||
|
#include <kiwano/core/ObjectBase.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(SoundPlayer);
|
KGE_DECLARE_SMART_PTR(SoundPlayer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Audio
|
* \addtogroup Audio
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频播放器
|
* @brief 音频播放器
|
||||||
*/
|
*/
|
||||||
class KGE_API SoundPlayer
|
class KGE_API SoundPlayer : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
public:
|
||||||
public:
|
SoundPlayer();
|
||||||
SoundPlayer();
|
|
||||||
|
|
||||||
~SoundPlayer();
|
~SoundPlayer();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载本地音频文件
|
/// @brief 加载本地音频文件
|
||||||
/// @param file_path 本地音频文件路径
|
/// @param file_path 本地音频文件路径
|
||||||
/// @return 音频标识符
|
/// @return 音频标识符
|
||||||
size_t Load(String const& file_path);
|
size_t Load(String const& file_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载音频资源
|
/// @brief 加载音频资源
|
||||||
/// @param res 音频资源
|
/// @param res 音频资源
|
||||||
/// @return 音频标识符
|
/// @return 音频标识符
|
||||||
size_t Load(Resource const& res);
|
size_t Load(Resource const& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 播放音频
|
/// @brief 播放音频
|
||||||
/// @param id 音频标识符
|
/// @param id 音频标识符
|
||||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||||
void Play(size_t id, int loop_count = 0);
|
void Play(size_t id, int loop_count = 0);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 暂停音频
|
/// @brief 暂停音频
|
||||||
/// @param id 音频标识符
|
/// @param id 音频标识符
|
||||||
void Pause(size_t id);
|
void Pause(size_t id);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 继续播放音频
|
/// @brief 继续播放音频
|
||||||
/// @param id 音频标识符
|
/// @param id 音频标识符
|
||||||
void Resume(size_t id);
|
void Resume(size_t id);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 停止音频
|
/// @brief 停止音频
|
||||||
/// @param id 音频标识符
|
/// @param id 音频标识符
|
||||||
void Stop(size_t id);
|
void Stop(size_t id);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取音频播放状态
|
/// @brief 获取音频播放状态
|
||||||
/// @param id 音频标识符
|
/// @param id 音频标识符
|
||||||
bool IsPlaying(size_t id);
|
bool IsPlaying(size_t id);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取音量
|
/// @brief 获取音量
|
||||||
float GetVolume() const;
|
float GetVolume() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置音量
|
/// @brief 设置音量
|
||||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||||
void SetVolume(float volume);
|
void SetVolume(float volume);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 暂停所有音频
|
/// @brief 暂停所有音频
|
||||||
void PauseAll();
|
void PauseAll();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 继续播放所有音频
|
/// @brief 继续播放所有音频
|
||||||
void ResumeAll();
|
void ResumeAll();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 停止所有音频
|
/// @brief 停止所有音频
|
||||||
void StopAll();
|
void StopAll();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 清除缓存
|
/// @brief 清除缓存
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float volume_;
|
float volume_;
|
||||||
|
|
||||||
using SoundMap = Map<size_t, SoundPtr>;
|
using SoundMap = Map<size_t, SoundPtr>;
|
||||||
SoundMap sound_cache_;
|
SoundMap sound_cache_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
} // namespace audio
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,280 +19,252 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#ifndef INITGUID
|
#ifndef INITGUID
|
||||||
# define INITGUID // MFAudioFormat_PCM, MF_MT_MAJOR_TYPE, MF_MT_SUBTYPE, MFMediaType_Audio
|
#define INITGUID // MFAudioFormat_PCM, MF_MT_MAJOR_TYPE, MF_MT_SUBTYPE, MFMediaType_Audio
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <kiwano/macros.h>
|
#include <kiwano-audio/Transcoder.h>
|
||||||
#include <kiwano/core/common.h>
|
#include <kiwano-audio/libraries.h>
|
||||||
#include <kiwano/core/Resource.h>
|
#include <kiwano/core/Common.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
|
#include <kiwano/core/Resource.h>
|
||||||
|
#include <kiwano/macros.h>
|
||||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||||
#include <kiwano/platform/win32/libraries.h>
|
#include <kiwano/platform/win32/libraries.h>
|
||||||
#include <kiwano-audio/libraries.h>
|
|
||||||
#include <kiwano-audio/Transcoder.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
|
|
||||||
Transcoder::Transcoder()
|
Transcoder::Transcoder()
|
||||||
: wave_format_(nullptr)
|
: wave_format_(nullptr)
|
||||||
, wave_data_(nullptr)
|
, wave_data_(nullptr)
|
||||||
, wave_size_(0)
|
, wave_size_(0)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Transcoder::~Transcoder()
|
|
||||||
{
|
|
||||||
ClearBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Transcoder::Buffer Transcoder::GetBuffer() const
|
|
||||||
{
|
|
||||||
return Buffer{ wave_data_, wave_size_, wave_format_ };
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transcoder::ClearBuffer()
|
|
||||||
{
|
|
||||||
if (wave_format_)
|
|
||||||
{
|
|
||||||
::CoTaskMemFree(wave_format_);
|
|
||||||
wave_format_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wave_data_)
|
|
||||||
{
|
|
||||||
delete[] wave_data_;
|
|
||||||
wave_data_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
wave_size_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT Transcoder::LoadMediaFile(String const& file_path)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
ComPtr<IMFSourceReader> reader;
|
|
||||||
|
|
||||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL(
|
|
||||||
file_path.c_str(),
|
|
||||||
nullptr,
|
|
||||||
&reader
|
|
||||||
);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = ReadSource(reader.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT Transcoder::LoadMediaResource(Resource const& res)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
ComPtr<IStream> stream;
|
|
||||||
ComPtr<IMFByteStream> byte_stream;
|
|
||||||
ComPtr<IMFSourceReader> reader;
|
|
||||||
|
|
||||||
Resource::Data data = res.GetData();
|
|
||||||
if (!data) { return E_FAIL; }
|
|
||||||
|
|
||||||
stream = win32::dlls::Shlwapi::Get().SHCreateMemStream(
|
|
||||||
static_cast<const BYTE*>(data.buffer),
|
|
||||||
static_cast<uint32_t>(data.size)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (stream == nullptr)
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"SHCreateMemStream failed");
|
|
||||||
return E_OUTOFMEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(
|
|
||||||
byte_stream.get(),
|
|
||||||
nullptr,
|
|
||||||
&reader
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = ReadSource(reader.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT Transcoder::ReadSource(IMFSourceReader* reader)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
DWORD max_stream_size = 0;
|
|
||||||
|
|
||||||
ComPtr<IMFMediaType> partial_type;
|
|
||||||
ComPtr<IMFMediaType> uncompressed_type;
|
|
||||||
|
|
||||||
hr = dlls::MediaFoundation::Get().MFCreateMediaType(&partial_type);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = partial_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = partial_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置 source reader 的媒体类型,它将使用合适的解码器去解码这个音频
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = reader->SetCurrentMediaType(
|
|
||||||
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
|
||||||
0,
|
|
||||||
partial_type.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 IMFMediaType 中获取 WAVEFORMAT 结构
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = reader->GetCurrentMediaType(
|
|
||||||
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
|
||||||
&uncompressed_type
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 指定音频流
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = reader->SetStreamSelection(
|
|
||||||
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 WAVEFORMAT 数据
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
uint32_t size = 0;
|
|
||||||
hr = dlls::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType(
|
|
||||||
uncompressed_type.get(),
|
|
||||||
&wave_format_,
|
|
||||||
&size,
|
|
||||||
(DWORD)MFWaveFormatExConvertFlag_Normal
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 估算音频流大小
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
PROPVARIANT prop;
|
|
||||||
PropVariantInit(&prop);
|
|
||||||
|
|
||||||
hr = reader->GetPresentationAttribute(
|
|
||||||
(DWORD)MF_SOURCE_READER_MEDIASOURCE,
|
|
||||||
MF_PD_DURATION,
|
|
||||||
&prop
|
|
||||||
);
|
|
||||||
|
|
||||||
LONGLONG duration = prop.uhVal.QuadPart;
|
|
||||||
max_stream_size = static_cast<DWORD>(
|
|
||||||
(duration * wave_format_->nAvgBytesPerSec) / 10000000 + 1
|
|
||||||
);
|
|
||||||
PropVariantClear(&prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取音频数据
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
DWORD flags = 0;
|
|
||||||
DWORD position = 0;
|
|
||||||
BYTE* data = new (std::nothrow) BYTE[max_stream_size];
|
|
||||||
|
|
||||||
ComPtr<IMFSample> sample;
|
|
||||||
ComPtr<IMFMediaBuffer> buffer;
|
|
||||||
|
|
||||||
if (data == nullptr)
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"Low memory");
|
|
||||||
hr = E_OUTOFMEMORY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
hr = reader->ReadSample(
|
|
||||||
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
&flags,
|
|
||||||
nullptr,
|
|
||||||
&sample
|
|
||||||
);
|
|
||||||
|
|
||||||
if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { break; }
|
|
||||||
|
|
||||||
if (sample == nullptr) { continue; }
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = sample->ConvertToContiguousBuffer(&buffer);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
BYTE* audio_data = nullptr;
|
|
||||||
DWORD sample_buffer_length = 0;
|
|
||||||
|
|
||||||
hr = buffer->Lock(
|
|
||||||
&audio_data,
|
|
||||||
nullptr,
|
|
||||||
&sample_buffer_length
|
|
||||||
);
|
|
||||||
|
|
||||||
if (position + sample_buffer_length >= max_stream_size)
|
|
||||||
{
|
|
||||||
hr = E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
::memcpy(data + position, audio_data, sample_buffer_length);
|
|
||||||
position += sample_buffer_length;
|
|
||||||
hr = buffer->Unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer = nullptr;
|
|
||||||
}
|
|
||||||
sample = nullptr;
|
|
||||||
|
|
||||||
if (FAILED(hr)) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
wave_data_ = data;
|
|
||||||
wave_size_ = position;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete[] data;
|
|
||||||
data = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transcoder::~Transcoder()
|
||||||
|
{
|
||||||
|
ClearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transcoder::Buffer Transcoder::GetBuffer() const
|
||||||
|
{
|
||||||
|
return Buffer{ wave_data_, wave_size_, wave_format_ };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transcoder::ClearBuffer()
|
||||||
|
{
|
||||||
|
if (wave_format_)
|
||||||
|
{
|
||||||
|
::CoTaskMemFree(wave_format_);
|
||||||
|
wave_format_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wave_data_)
|
||||||
|
{
|
||||||
|
delete[] wave_data_;
|
||||||
|
wave_data_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wave_size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Transcoder::LoadMediaFile(String const& file_path)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
ComPtr<IMFSourceReader> reader;
|
||||||
|
|
||||||
|
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL(file_path.c_str(), nullptr, &reader);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = ReadSource(reader.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Transcoder::LoadMediaResource(Resource const& res)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
ComPtr<IStream> stream;
|
||||||
|
ComPtr<IMFByteStream> byte_stream;
|
||||||
|
ComPtr<IMFSourceReader> reader;
|
||||||
|
|
||||||
|
Resource::Data data = res.GetData();
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = win32::dlls::Shlwapi::Get().SHCreateMemStream(static_cast<const BYTE*>(data.buffer),
|
||||||
|
static_cast<uint32_t>(data.size));
|
||||||
|
|
||||||
|
if (stream == nullptr)
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"SHCreateMemStream failed");
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(byte_stream.get(), nullptr, &reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = ReadSource(reader.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Transcoder::ReadSource(IMFSourceReader* reader)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
DWORD max_stream_size = 0;
|
||||||
|
|
||||||
|
ComPtr<IMFMediaType> partial_type;
|
||||||
|
ComPtr<IMFMediaType> uncompressed_type;
|
||||||
|
|
||||||
|
hr = dlls::MediaFoundation::Get().MFCreateMediaType(&partial_type);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = partial_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = partial_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 source reader 的媒体类型,它将使用合适的解码器去解码这个音频
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, partial_type.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 IMFMediaType 中获取 WAVEFORMAT 结构
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = reader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &uncompressed_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指定音频流
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = reader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 WAVEFORMAT 数据
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
uint32_t size = 0;
|
||||||
|
hr = dlls::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType(
|
||||||
|
uncompressed_type.get(), &wave_format_, &size, (DWORD)MFWaveFormatExConvertFlag_Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 估算音频流大小
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
PROPVARIANT prop;
|
||||||
|
PropVariantInit(&prop);
|
||||||
|
|
||||||
|
hr = reader->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &prop);
|
||||||
|
|
||||||
|
LONGLONG duration = prop.uhVal.QuadPart;
|
||||||
|
max_stream_size = static_cast<DWORD>((duration * wave_format_->nAvgBytesPerSec) / 10000000 + 1);
|
||||||
|
PropVariantClear(&prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取音频数据
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
DWORD flags = 0;
|
||||||
|
DWORD position = 0;
|
||||||
|
BYTE* data = new (std::nothrow) BYTE[max_stream_size];
|
||||||
|
|
||||||
|
ComPtr<IMFSample> sample;
|
||||||
|
ComPtr<IMFMediaBuffer> buffer;
|
||||||
|
|
||||||
|
if (data == nullptr)
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"Low memory");
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
hr = reader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &flags, nullptr,
|
||||||
|
&sample);
|
||||||
|
|
||||||
|
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sample == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = sample->ConvertToContiguousBuffer(&buffer);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
BYTE* audio_data = nullptr;
|
||||||
|
DWORD sample_buffer_length = 0;
|
||||||
|
|
||||||
|
hr = buffer->Lock(&audio_data, nullptr, &sample_buffer_length);
|
||||||
|
|
||||||
|
if (position + sample_buffer_length >= max_stream_size)
|
||||||
|
{
|
||||||
|
hr = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
::memcpy(data + position, audio_data, sample_buffer_length);
|
||||||
|
position += sample_buffer_length;
|
||||||
|
hr = buffer->Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer = nullptr;
|
||||||
|
}
|
||||||
|
sample = nullptr;
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
wave_data_ = data;
|
||||||
|
wave_size_ = position;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete[] data;
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -26,66 +26,66 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
class Sound;
|
class Sound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Audio
|
* \addtogroup Audio
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频解码器
|
* @brief 音频解码器
|
||||||
*/
|
*/
|
||||||
class KGE_API Transcoder
|
class KGE_API Transcoder
|
||||||
{
|
{
|
||||||
friend class Sound;
|
friend class Sound;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频数据缓冲
|
* @brief 音频数据缓冲
|
||||||
*/
|
*/
|
||||||
struct Buffer
|
struct Buffer
|
||||||
{
|
{
|
||||||
BYTE* data; ///< 音频数据
|
BYTE* data; ///< 音频数据
|
||||||
uint32_t size; ///< 音频数据大小
|
uint32_t size; ///< 音频数据大小
|
||||||
const WAVEFORMATEX* format; ///< 音频数据格式
|
const WAVEFORMATEX* format; ///< 音频数据格式
|
||||||
};
|
};
|
||||||
|
|
||||||
Transcoder();
|
Transcoder();
|
||||||
|
|
||||||
~Transcoder();
|
~Transcoder();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取数据缓冲
|
/// @brief 获取数据缓冲
|
||||||
Buffer GetBuffer() const;
|
Buffer GetBuffer() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 清空数据缓冲
|
/// @brief 清空数据缓冲
|
||||||
void ClearBuffer();
|
void ClearBuffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 解码本地音频文件
|
/// @brief 解码本地音频文件
|
||||||
HRESULT LoadMediaFile(String const& file_path);
|
HRESULT LoadMediaFile(String const& file_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 解码音频资源
|
/// @brief 解码音频资源
|
||||||
HRESULT LoadMediaResource(Resource const& res);
|
HRESULT LoadMediaResource(Resource const& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 读取音频源数据
|
/// @brief 读取音频源数据
|
||||||
HRESULT ReadSource(IMFSourceReader* reader);
|
HRESULT ReadSource(IMFSourceReader* reader);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BYTE* wave_data_;
|
BYTE* wave_data_;
|
||||||
uint32_t wave_size_;
|
uint32_t wave_size_;
|
||||||
WAVEFORMATEX* wave_format_;
|
WAVEFORMATEX* wave_format_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
} // namespace audio
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,81 +18,84 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/core/Logger.h>
|
|
||||||
#include <kiwano-audio/libraries.h>
|
#include <kiwano-audio/libraries.h>
|
||||||
|
#include <kiwano/core/Logger.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
namespace dlls
|
namespace dlls
|
||||||
{
|
{
|
||||||
XAudio2::XAudio2()
|
XAudio2::XAudio2()
|
||||||
: xaudio2()
|
: xaudio2()
|
||||||
, XAudio2Create(nullptr)
|
, XAudio2Create(nullptr)
|
||||||
{
|
{
|
||||||
const auto xaudio2_dll_names =
|
const auto xaudio2_dll_names = {
|
||||||
{
|
"xaudio2_9.dll", // for Windows 10
|
||||||
"xaudio2_9.dll", // for Windows 10
|
"xaudio2_8.dll", // for Windows 8
|
||||||
"xaudio2_8.dll", // for Windows 8
|
"xaudio2_7.dll" // for DirectX SDK
|
||||||
"xaudio2_7.dll" // for DirectX SDK
|
};
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& name : xaudio2_dll_names)
|
for (const auto& name : xaudio2_dll_names)
|
||||||
{
|
{
|
||||||
if (xaudio2.Load(name))
|
if (xaudio2.Load(name))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xaudio2.IsValid())
|
if (xaudio2.IsValid())
|
||||||
{
|
{
|
||||||
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("XAudio2Create");
|
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("XAudio2Create");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
KGE_ERROR(L"Load xaudio2.dll failed");
|
KGE_ERROR(L"Load xaudio2.dll failed");
|
||||||
throw std::runtime_error("Load xaudio2.dll failed");
|
throw std::runtime_error("Load xaudio2.dll failed");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MediaFoundation::MediaFoundation()
|
|
||||||
: mfplat()
|
|
||||||
, mfreadwrite()
|
|
||||||
, MFStartup(nullptr)
|
|
||||||
, MFShutdown(nullptr)
|
|
||||||
, MFCreateMediaType(nullptr)
|
|
||||||
, MFCreateWaveFormatExFromMFMediaType(nullptr)
|
|
||||||
, MFCreateSourceReaderFromURL(nullptr)
|
|
||||||
, MFCreateSourceReaderFromByteStream(nullptr)
|
|
||||||
, MFCreateMFByteStreamOnStream(nullptr)
|
|
||||||
{
|
|
||||||
if (mfplat.Load("Mfplat.dll"))
|
|
||||||
{
|
|
||||||
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_ERROR(L"Load Mfplat.dll failed");
|
|
||||||
throw std::runtime_error("Load Mfplat.dll failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mfreadwrite.Load("Mfreadwrite.dll"))
|
|
||||||
{
|
|
||||||
MFCreateSourceReaderFromURL = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromURL>("MFCreateSourceReaderFromURL");
|
|
||||||
MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>("MFCreateSourceReaderFromByteStream");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KGE_ERROR(L"Load Mfreadwrite.dll failed");
|
|
||||||
throw std::runtime_error("Load Mfreadwrite.dll failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaFoundation::MediaFoundation()
|
||||||
|
: mfplat()
|
||||||
|
, mfreadwrite()
|
||||||
|
, MFStartup(nullptr)
|
||||||
|
, MFShutdown(nullptr)
|
||||||
|
, MFCreateMediaType(nullptr)
|
||||||
|
, MFCreateWaveFormatExFromMFMediaType(nullptr)
|
||||||
|
, MFCreateSourceReaderFromURL(nullptr)
|
||||||
|
, MFCreateSourceReaderFromByteStream(nullptr)
|
||||||
|
, MFCreateMFByteStreamOnStream(nullptr)
|
||||||
|
{
|
||||||
|
if (mfplat.Load("Mfplat.dll"))
|
||||||
|
{
|
||||||
|
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_ERROR(L"Load Mfplat.dll failed");
|
||||||
|
throw std::runtime_error("Load Mfplat.dll failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mfreadwrite.Load("Mfreadwrite.dll"))
|
||||||
|
{
|
||||||
|
MFCreateSourceReaderFromURL =
|
||||||
|
mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromURL>("MFCreateSourceReaderFromURL");
|
||||||
|
MFCreateSourceReaderFromByteStream =
|
||||||
|
mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>("MFCreateSourceReaderFromByteStream");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KGE_ERROR(L"Load Mfreadwrite.dll failed");
|
||||||
|
throw std::runtime_error("Load Mfreadwrite.dll failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace dlls
|
||||||
|
} // namespace audio
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,80 +20,79 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/Library.h>
|
#include <kiwano/core/Library.h>
|
||||||
#include <xaudio2.h>
|
|
||||||
#include <mfapi.h>
|
#include <mfapi.h>
|
||||||
#include <mfidl.h>
|
#include <mfidl.h>
|
||||||
#include <mfreadwrite.h>
|
#include <mfreadwrite.h>
|
||||||
|
#include <xaudio2.h>
|
||||||
|
|
||||||
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
|
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
namespace dlls
|
namespace dlls
|
||||||
{
|
{
|
||||||
class KGE_API XAudio2
|
class KGE_API XAudio2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static inline XAudio2& Get()
|
static inline XAudio2& Get()
|
||||||
{
|
{
|
||||||
static XAudio2 instance;
|
static XAudio2 instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XAudio2 functions
|
// XAudio2 functions
|
||||||
typedef HRESULT(WINAPI* PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
|
typedef HRESULT(WINAPI* PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
|
||||||
|
|
||||||
PFN_XAudio2Create XAudio2Create;
|
PFN_XAudio2Create XAudio2Create;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XAudio2();
|
XAudio2();
|
||||||
|
|
||||||
XAudio2(const XAudio2&) = delete;
|
XAudio2(const XAudio2&) = delete;
|
||||||
XAudio2& operator=(const XAudio2&) = delete;
|
XAudio2& operator=(const XAudio2&) = delete;
|
||||||
|
|
||||||
Library xaudio2;
|
Library xaudio2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class KGE_API MediaFoundation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline MediaFoundation& Get()
|
||||||
|
{
|
||||||
|
static MediaFoundation instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
class KGE_API MediaFoundation
|
// MediaFoundation functions
|
||||||
{
|
typedef HRESULT(WINAPI* PFN_MFStartup)(ULONG, DWORD);
|
||||||
public:
|
typedef HRESULT(WINAPI* PFN_MFShutdown)();
|
||||||
static inline MediaFoundation& Get()
|
typedef HRESULT(WINAPI* PFN_MFCreateMediaType)(IMFMediaType**);
|
||||||
{
|
typedef HRESULT(WINAPI* PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
|
||||||
static MediaFoundation instance;
|
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
|
||||||
return instance;
|
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
|
||||||
}
|
typedef HRESULT(WINAPI* PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
|
||||||
|
|
||||||
// MediaFoundation functions
|
PFN_MFStartup MFStartup;
|
||||||
typedef HRESULT(WINAPI* PFN_MFStartup)(ULONG, DWORD);
|
PFN_MFShutdown MFShutdown;
|
||||||
typedef HRESULT(WINAPI* PFN_MFShutdown)();
|
PFN_MFCreateMediaType MFCreateMediaType;
|
||||||
typedef HRESULT(WINAPI* PFN_MFCreateMediaType)(IMFMediaType**);
|
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
|
||||||
typedef HRESULT(WINAPI* PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
|
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
|
||||||
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
|
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
|
||||||
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
|
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
|
||||||
typedef HRESULT(WINAPI* PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
|
|
||||||
|
|
||||||
PFN_MFStartup MFStartup;
|
private:
|
||||||
PFN_MFShutdown MFShutdown;
|
MediaFoundation();
|
||||||
PFN_MFCreateMediaType MFCreateMediaType;
|
|
||||||
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
|
|
||||||
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
|
|
||||||
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
|
|
||||||
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
|
|
||||||
|
|
||||||
private:
|
MediaFoundation(const MediaFoundation&) = delete;
|
||||||
MediaFoundation();
|
MediaFoundation& operator=(const MediaFoundation&) = delete;
|
||||||
|
|
||||||
MediaFoundation(const MediaFoundation&) = delete;
|
Library mfplat;
|
||||||
MediaFoundation& operator=(const MediaFoundation&) = delete;
|
Library mfreadwrite;
|
||||||
|
};
|
||||||
Library mfplat;
|
} // namespace dlls
|
||||||
Library mfreadwrite;
|
} // namespace audio
|
||||||
};
|
} // namespace kiwano
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,43 +22,45 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace imgui
|
namespace imgui
|
||||||
{
|
{
|
||||||
ImGuiLayer::ImGuiLayer()
|
ImGuiLayer::ImGuiLayer()
|
||||||
{
|
{
|
||||||
SetSwallowEvents(true);
|
SetSwallowEvents(true);
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiLayer::~ImGuiLayer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiLayer::OnRender(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
PrepareToRender(rt);
|
|
||||||
for (const auto& pipeline : pipelines_)
|
|
||||||
{
|
|
||||||
pipeline.second();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiLayer::AddItem(ImGuiPipeline const& item, String const& name)
|
|
||||||
{
|
|
||||||
pipelines_.insert(std::make_pair(name, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiLayer::RemoveItem(String const& name)
|
|
||||||
{
|
|
||||||
auto iter = pipelines_.find(name);
|
|
||||||
if (iter != pipelines_.end())
|
|
||||||
{
|
|
||||||
pipelines_.erase(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiLayer::RemoveAllItems()
|
|
||||||
{
|
|
||||||
pipelines_.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGuiLayer::~ImGuiLayer() {}
|
||||||
|
|
||||||
|
void ImGuiLayer::OnRender(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
for (const auto& pipeline : pipelines_)
|
||||||
|
{
|
||||||
|
pipeline.second();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiLayer::CheckVisibility(RenderContext& ctx) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiLayer::AddItem(String const& name, ImGuiPipeline const& item)
|
||||||
|
{
|
||||||
|
pipelines_.insert(std::make_pair(name, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiLayer::RemoveItem(String const& name)
|
||||||
|
{
|
||||||
|
auto iter = pipelines_.find(name);
|
||||||
|
if (iter != pipelines_.end())
|
||||||
|
{
|
||||||
|
pipelines_.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiLayer::RemoveAllItems()
|
||||||
|
{
|
||||||
|
pipelines_.clear();
|
||||||
|
}
|
||||||
|
} // namespace imgui
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,47 +23,48 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace imgui
|
namespace imgui
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(ImGuiLayer);
|
KGE_DECLARE_SMART_PTR(ImGuiLayer);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief ImGui管道
|
/// @brief ImGui管道
|
||||||
using ImGuiPipeline = Function<void()>;
|
using ImGuiPipeline = Function<void()>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief ImGui图层
|
* @brief ImGui图层
|
||||||
*/
|
*/
|
||||||
class ImGuiLayer
|
class ImGuiLayer : public Layer
|
||||||
: public Layer
|
{
|
||||||
{
|
public:
|
||||||
public:
|
ImGuiLayer();
|
||||||
ImGuiLayer();
|
|
||||||
|
|
||||||
virtual ~ImGuiLayer();
|
virtual ~ImGuiLayer();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加 ImGui 元素
|
/// @brief 添加 ImGui 元素
|
||||||
/// @param item 管道
|
/// @param name 元素名称
|
||||||
/// @param name 元素名称
|
/// @param item 管道
|
||||||
void AddItem(ImGuiPipeline const& item, String const& name);
|
void AddItem(String const& name, ImGuiPipeline const& item);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 移除 ImGui 元素
|
/// @brief 移除 ImGui 元素
|
||||||
/// @param name 元素名称
|
/// @param name 元素名称
|
||||||
void RemoveItem(String const& name);
|
void RemoveItem(String const& name);
|
||||||
|
|
||||||
// 移除所有元素
|
// 移除所有元素
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 移除所有元素
|
/// @brief 移除所有元素
|
||||||
void RemoveAllItems();
|
void RemoveAllItems();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void OnRender(RenderTarget* rt) override;
|
void OnRender(RenderContext& ctx) override;
|
||||||
|
|
||||||
private:
|
bool CheckVisibility(RenderContext& ctx) const override;
|
||||||
Map<String, ImGuiPipeline> pipelines_;
|
|
||||||
};
|
private:
|
||||||
}
|
Map<String, ImGuiPipeline> pipelines_;
|
||||||
}
|
};
|
||||||
|
} // namespace imgui
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -1,309 +1,236 @@
|
||||||
// Copyright (C) 2019 Nomango
|
// Copyright (C) 2019 Nomango
|
||||||
|
|
||||||
#include <kiwano/core/common.h>
|
|
||||||
#include <kiwano/platform/Window.h>
|
#include <kiwano/core/Common.h>
|
||||||
|
#include <kiwano/core/event/KeyEvent.h>
|
||||||
|
#include <kiwano/core/event/MouseEvent.h>
|
||||||
#include <kiwano/platform/Input.h>
|
#include <kiwano/platform/Input.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/platform/Window.h>
|
||||||
|
#include <kiwano/render/Renderer.h>
|
||||||
#include <kiwano-imgui/ImGuiModule.h>
|
#include <kiwano-imgui/ImGuiModule.h>
|
||||||
#include <kiwano-imgui/imgui_impl.h>
|
#include <kiwano-imgui/imgui_impl.h>
|
||||||
|
|
||||||
#include <XInput.h>
|
|
||||||
#pragma comment(lib, "xinput")
|
|
||||||
|
|
||||||
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
|
|
||||||
#ifndef WM_MOUSEHWHEEL
|
|
||||||
# define WM_MOUSEHWHEEL 0x020E
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DBT_DEVNODES_CHANGED
|
|
||||||
# define DBT_DEVNODES_CHANGED 0x0007
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace imgui
|
namespace imgui
|
||||||
{
|
{
|
||||||
ImGuiModule::ImGuiModule()
|
ImGuiModule::ImGuiModule()
|
||||||
: has_gamepad_(false)
|
: target_window_(nullptr)
|
||||||
, want_update_has_gamepad_(false)
|
{
|
||||||
, target_window_(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::SetupComponent()
|
|
||||||
{
|
|
||||||
// Setup Dear ImGui context
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
|
||||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
|
||||||
|
|
||||||
// Setup Dear ImGui style
|
|
||||||
ImGui::StyleColorsDark();
|
|
||||||
//ImGui::StyleColorsClassic();
|
|
||||||
|
|
||||||
// Setup Platform/Renderer bindings
|
|
||||||
Init(Window::instance().GetHandle());
|
|
||||||
|
|
||||||
target_window_ = Renderer::instance().GetTargetWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::DestroyComponent()
|
|
||||||
{
|
|
||||||
ImGui_Impl_Shutdown();
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::OnUpdate(Duration dt)
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
// Setup time step
|
|
||||||
io.DeltaTime = dt.Seconds();
|
|
||||||
|
|
||||||
// Read keyboard modifiers inputs
|
|
||||||
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.
|
|
||||||
|
|
||||||
// Update OS mouse position
|
|
||||||
UpdateMousePos();
|
|
||||||
|
|
||||||
// Update OS mouse cursor with the cursor requested by imgui
|
|
||||||
UpdateMouseCursor();
|
|
||||||
|
|
||||||
// Update game controllers (if enabled and available)
|
|
||||||
UpdateGamepads();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::Init(HWND hwnd)
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
|
||||||
io.BackendPlatformName = "imgui_impl_win32";
|
|
||||||
io.ImeWindowHandle = hwnd;
|
|
||||||
|
|
||||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
|
||||||
io.KeyMap[ImGuiKey_Tab] = KeyCode::Tab;
|
|
||||||
io.KeyMap[ImGuiKey_LeftArrow] = KeyCode::Left;
|
|
||||||
io.KeyMap[ImGuiKey_RightArrow] = KeyCode::Right;
|
|
||||||
io.KeyMap[ImGuiKey_UpArrow] = KeyCode::Up;
|
|
||||||
io.KeyMap[ImGuiKey_DownArrow] = KeyCode::Down;
|
|
||||||
io.KeyMap[ImGuiKey_Delete] = KeyCode::Delete;
|
|
||||||
io.KeyMap[ImGuiKey_Backspace] = KeyCode::Back;
|
|
||||||
io.KeyMap[ImGuiKey_Space] = KeyCode::Space;
|
|
||||||
io.KeyMap[ImGuiKey_Enter] = KeyCode::Enter;
|
|
||||||
io.KeyMap[ImGuiKey_Escape] = KeyCode::Esc;
|
|
||||||
io.KeyMap[ImGuiKey_A] = KeyCode::A;
|
|
||||||
io.KeyMap[ImGuiKey_C] = KeyCode::C;
|
|
||||||
io.KeyMap[ImGuiKey_V] = KeyCode::V;
|
|
||||||
io.KeyMap[ImGuiKey_X] = KeyCode::X;
|
|
||||||
io.KeyMap[ImGuiKey_Y] = KeyCode::Y;
|
|
||||||
io.KeyMap[ImGuiKey_Z] = KeyCode::Z;
|
|
||||||
|
|
||||||
ImGui_Impl_Init(&Renderer::instance());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::BeforeRender()
|
|
||||||
{
|
|
||||||
NewFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::AfterRender()
|
|
||||||
{
|
|
||||||
Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
|
|
||||||
{
|
|
||||||
if (ImGui::GetCurrentContext() == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
|
|
||||||
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
|
|
||||||
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
|
|
||||||
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
|
|
||||||
{
|
|
||||||
int button = 0;
|
|
||||||
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
|
|
||||||
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
|
|
||||||
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
|
|
||||||
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wparam) == XBUTTON1) ? 3 : 4; }
|
|
||||||
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
|
|
||||||
::SetCapture(hwnd);
|
|
||||||
|
|
||||||
io.MouseDown[button] = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
case WM_RBUTTONUP:
|
|
||||||
case WM_MBUTTONUP:
|
|
||||||
case WM_XBUTTONUP:
|
|
||||||
{
|
|
||||||
int button = 0;
|
|
||||||
if (msg == WM_LBUTTONUP) { button = 0; }
|
|
||||||
if (msg == WM_RBUTTONUP) { button = 1; }
|
|
||||||
if (msg == WM_MBUTTONUP) { button = 2; }
|
|
||||||
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wparam) == XBUTTON1) ? 3 : 4; }
|
|
||||||
io.MouseDown[button] = false;
|
|
||||||
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
|
|
||||||
::ReleaseCapture();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_MOUSEWHEEL:
|
|
||||||
{
|
|
||||||
io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_MOUSEHWHEEL:
|
|
||||||
{
|
|
||||||
io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_KEYDOWN:
|
|
||||||
case WM_SYSKEYDOWN:
|
|
||||||
{
|
|
||||||
if (wparam < 256)
|
|
||||||
io.KeysDown[wparam] = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_KEYUP:
|
|
||||||
case WM_SYSKEYUP:
|
|
||||||
{
|
|
||||||
if (wparam < 256)
|
|
||||||
io.KeysDown[wparam] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_CHAR:
|
|
||||||
{
|
|
||||||
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
|
||||||
io.AddInputCharacter((uint32_t)wparam);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_SETCURSOR:
|
|
||||||
{
|
|
||||||
if (LOWORD(lparam) == HTCLIENT)
|
|
||||||
{
|
|
||||||
UpdateMouseCursor();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_DEVICECHANGE:
|
|
||||||
{
|
|
||||||
if ((uint32_t)wparam == DBT_DEVNODES_CHANGED)
|
|
||||||
want_update_has_gamepad_ = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::NewFrame()
|
|
||||||
{
|
|
||||||
ImGui_Impl_NewFrame();
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!");
|
|
||||||
|
|
||||||
// Setup display size (every frame to accommodate for window resizing)
|
|
||||||
Size display_size = Renderer::instance().GetOutputSize();
|
|
||||||
io.DisplaySize = ImVec2(display_size.x, display_size.y);
|
|
||||||
|
|
||||||
ImGui::NewFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::Render()
|
|
||||||
{
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
ImGui_Impl_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::UpdateMousePos()
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
|
||||||
if (io.WantSetMousePos)
|
|
||||||
{
|
|
||||||
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
|
|
||||||
::ClientToScreen(target_window_, &pos);
|
|
||||||
::SetCursorPos(pos.x, pos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point pos = Input::instance().GetMousePos();
|
|
||||||
io.MousePos = ImVec2(pos.x, pos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGuiModule::UpdateMouseCursor()
|
|
||||||
{
|
|
||||||
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CursorType cursor = CursorType::Arrow;
|
|
||||||
switch (ImGui::GetMouseCursor())
|
|
||||||
{
|
|
||||||
case ImGuiMouseCursor_Arrow: cursor = CursorType::Arrow; break;
|
|
||||||
case ImGuiMouseCursor_TextInput: cursor = CursorType::TextInput; break;
|
|
||||||
case ImGuiMouseCursor_ResizeAll: cursor = CursorType::SizeAll; break;
|
|
||||||
case ImGuiMouseCursor_ResizeEW: cursor = CursorType::SizeWE; break;
|
|
||||||
case ImGuiMouseCursor_ResizeNS: cursor = CursorType::SizeNS; break;
|
|
||||||
case ImGuiMouseCursor_ResizeNESW: cursor = CursorType::SizeNESW; break;
|
|
||||||
case ImGuiMouseCursor_ResizeNWSE: cursor = CursorType::SizeNWSE; break;
|
|
||||||
case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window::instance().SetCursor(cursor);
|
|
||||||
}
|
|
||||||
void ImGuiModule::UpdateGamepads()
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
|
||||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
|
|
||||||
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
|
|
||||||
if (want_update_has_gamepad_)
|
|
||||||
{
|
|
||||||
XINPUT_CAPABILITIES caps;
|
|
||||||
has_gamepad_ = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
|
|
||||||
want_update_has_gamepad_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
XINPUT_STATE xinput_state;
|
|
||||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
|
||||||
if (has_gamepad_ && XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
|
||||||
|
|
||||||
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
|
|
||||||
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
|
||||||
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
|
|
||||||
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
|
|
||||||
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
|
|
||||||
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
|
|
||||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
|
|
||||||
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
|
|
||||||
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
|
|
||||||
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
|
|
||||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
|
||||||
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
|
||||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
|
||||||
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
|
||||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
|
||||||
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
|
||||||
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
|
||||||
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
|
|
||||||
#undef MAP_BUTTON
|
|
||||||
#undef MAP_ANALOG
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::SetupComponent()
|
||||||
|
{
|
||||||
|
// Setup Dear ImGui context
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
(void)io;
|
||||||
|
|
||||||
|
// Setup Dear ImGui style
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
|
// Setup Platform/Renderer bindings
|
||||||
|
target_window_ = Renderer::Instance().GetTargetWindow();
|
||||||
|
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |=
|
||||||
|
ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_win32";
|
||||||
|
io.ImeWindowHandle = target_window_;
|
||||||
|
|
||||||
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during
|
||||||
|
// the application lifetime.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = (int)KeyCode::Tab;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = (int)KeyCode::Left;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = (int)KeyCode::Right;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = (int)KeyCode::Up;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = (int)KeyCode::Down;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = (int)KeyCode::Delete;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = (int)KeyCode::Back;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = (int)KeyCode::Space;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = (int)KeyCode::Enter;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = (int)KeyCode::Esc;
|
||||||
|
io.KeyMap[ImGuiKey_A] = (int)KeyCode::A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = (int)KeyCode::C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = (int)KeyCode::V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = (int)KeyCode::X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = (int)KeyCode::Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = (int)KeyCode::Z;
|
||||||
|
|
||||||
|
ImGui_Impl_Init(Renderer::Instance());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::DestroyComponent()
|
||||||
|
{
|
||||||
|
ImGui_Impl_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::OnUpdate(Duration dt)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
io.DeltaTime = dt.Seconds();
|
||||||
|
|
||||||
|
// Read keyboard modifiers inputs
|
||||||
|
io.KeyCtrl = Input::Instance().IsDown(KeyCode::Ctrl);
|
||||||
|
io.KeyShift = Input::Instance().IsDown(KeyCode::Shift);
|
||||||
|
io.KeyAlt = Input::Instance().IsDown(KeyCode::Alt);
|
||||||
|
io.KeySuper = Input::Instance().IsDown(KeyCode::Super);
|
||||||
|
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the HandleEvent function below.
|
||||||
|
|
||||||
|
// Update OS mouse position
|
||||||
|
UpdateMousePos();
|
||||||
|
|
||||||
|
// Update OS mouse cursor with the cursor requested by imgui
|
||||||
|
UpdateMouseCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::BeforeRender()
|
||||||
|
{
|
||||||
|
NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::AfterRender()
|
||||||
|
{
|
||||||
|
Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::HandleEvent(Event* evt)
|
||||||
|
{
|
||||||
|
if (ImGui::GetCurrentContext() == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (evt->IsType<MouseEvent>())
|
||||||
|
{
|
||||||
|
if (evt->IsType<MouseDownEvent>())
|
||||||
|
{
|
||||||
|
MouseButton button = dynamic_cast<MouseDownEvent*>(evt)->button;
|
||||||
|
int index = 0;
|
||||||
|
if (button == MouseButton::Left)
|
||||||
|
index = 0;
|
||||||
|
else if (button == MouseButton::Right)
|
||||||
|
index = 1;
|
||||||
|
else if (button == MouseButton::Middle)
|
||||||
|
index = 2;
|
||||||
|
io.MouseDown[index] = true;
|
||||||
|
}
|
||||||
|
else if (evt->IsType<MouseUpEvent>())
|
||||||
|
{
|
||||||
|
MouseButton button = dynamic_cast<MouseUpEvent*>(evt)->button;
|
||||||
|
int index = 0;
|
||||||
|
if (button == MouseButton::Left)
|
||||||
|
index = 0;
|
||||||
|
else if (button == MouseButton::Right)
|
||||||
|
index = 1;
|
||||||
|
else if (button == MouseButton::Middle)
|
||||||
|
index = 2;
|
||||||
|
io.MouseDown[index] = false;
|
||||||
|
}
|
||||||
|
else if (evt->IsType<MouseWheelEvent>())
|
||||||
|
{
|
||||||
|
float wheel = dynamic_cast<MouseWheelEvent*>(evt)->wheel;
|
||||||
|
io.MouseWheel += wheel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (evt->IsType<KeyEvent>())
|
||||||
|
{
|
||||||
|
if (evt->IsType<KeyDownEvent>())
|
||||||
|
{
|
||||||
|
KeyCode key = dynamic_cast<KeyDownEvent*>(evt)->code;
|
||||||
|
io.KeysDown[(int)key] = true;
|
||||||
|
}
|
||||||
|
else if (evt->IsType<KeyUpEvent>())
|
||||||
|
{
|
||||||
|
KeyCode key = dynamic_cast<KeyUpEvent*>(evt)->code;
|
||||||
|
io.KeysDown[(int)key] = false;
|
||||||
|
}
|
||||||
|
else if (evt->IsType<KeyCharEvent>())
|
||||||
|
{
|
||||||
|
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||||
|
char ch = dynamic_cast<KeyCharEvent*>(evt)->value;
|
||||||
|
io.AddInputCharacter(static_cast<ImWchar>(ch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_Impl_NewFrame();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
Size display_size = Renderer::Instance().GetOutputSize();
|
||||||
|
io.DisplaySize = ImVec2(display_size.x, display_size.y);
|
||||||
|
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::Render()
|
||||||
|
{
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
ImGui_Impl_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::UpdateMousePos()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by
|
||||||
|
// user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
|
||||||
|
::ClientToScreen(target_window_, &pos);
|
||||||
|
::SetCursorPos(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point pos = Input::Instance().GetMousePos();
|
||||||
|
io.MousePos = ImVec2(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiModule::UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CursorType cursor = CursorType::Arrow;
|
||||||
|
switch (ImGui::GetMouseCursor())
|
||||||
|
{
|
||||||
|
case ImGuiMouseCursor_Arrow:
|
||||||
|
cursor = CursorType::Arrow;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_TextInput:
|
||||||
|
cursor = CursorType::TextInput;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeAll:
|
||||||
|
cursor = CursorType::SizeAll;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeEW:
|
||||||
|
cursor = CursorType::SizeWE;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeNS:
|
||||||
|
cursor = CursorType::SizeNS;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeNESW:
|
||||||
|
cursor = CursorType::SizeNESW;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeNWSE:
|
||||||
|
cursor = CursorType::SizeNWSE;
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_Hand:
|
||||||
|
cursor = CursorType::Hand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::Instance().SetCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace imgui
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,57 +19,51 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/common.h>
|
#include <kiwano/core/Common.h>
|
||||||
#include <kiwano/core/Component.h>
|
#include <kiwano/core/Component.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace imgui
|
namespace imgui
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief ImGuiÄ£¿é
|
* @brief ImGuiÄ£¿é
|
||||||
*/
|
*/
|
||||||
class ImGuiModule
|
class ImGuiModule
|
||||||
: public Singleton<ImGuiModule>
|
: public Singleton<ImGuiModule>
|
||||||
, public RenderComponent
|
, public RenderComponent
|
||||||
, public UpdateComponent
|
, public UpdateComponent
|
||||||
, public EventComponent
|
, public EventComponent
|
||||||
{
|
{
|
||||||
friend Singleton<ImGuiModule>;
|
friend Singleton<ImGuiModule>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ImGuiModule();
|
ImGuiModule();
|
||||||
|
|
||||||
void SetupComponent() override;
|
void SetupComponent() override;
|
||||||
|
|
||||||
void DestroyComponent() override;
|
void DestroyComponent() override;
|
||||||
|
|
||||||
void BeforeRender() override;
|
void BeforeRender() override;
|
||||||
|
|
||||||
void AfterRender() override;
|
void AfterRender() override;
|
||||||
|
|
||||||
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
|
void HandleEvent(Event* evt) override;
|
||||||
|
|
||||||
void OnUpdate(Duration dt) override;
|
void OnUpdate(Duration dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Init(HWND hwnd);
|
void NewFrame();
|
||||||
|
|
||||||
void NewFrame();
|
void Render();
|
||||||
|
|
||||||
void Render();
|
void UpdateMousePos();
|
||||||
|
|
||||||
void UpdateMousePos();
|
void UpdateMouseCursor();
|
||||||
|
|
||||||
void UpdateMouseCursor();
|
private:
|
||||||
|
WindowHandle target_window_;
|
||||||
void UpdateGamepads();
|
};
|
||||||
|
} // namespace imgui
|
||||||
private:
|
} // namespace kiwano
|
||||||
bool has_gamepad_;
|
|
||||||
bool want_update_has_gamepad_;
|
|
||||||
HWND target_window_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,25 +8,62 @@
|
||||||
|
|
||||||
#include <kiwano-imgui/imgui_impl_dx11.h>
|
#include <kiwano-imgui/imgui_impl_dx11.h>
|
||||||
|
|
||||||
inline bool ImGui_Impl_Init(::kiwano::Renderer* renderer) { return ImGui_ImplDX11_Init(renderer->GetD3DDeviceResources()->GetDevice(), renderer->GetD3DDeviceResources()->GetDeviceContext()); }
|
inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer)
|
||||||
inline void ImGui_Impl_Shutdown() { ImGui_ImplDX11_Shutdown(); }
|
{
|
||||||
inline void ImGui_Impl_NewFrame() { ImGui_ImplDX11_NewFrame(); }
|
return ImGui_ImplDX11_Init(renderer.GetD3DDeviceResources()->GetDevice(),
|
||||||
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data) { ImGui_ImplDX11_RenderDrawData(draw_data); }
|
renderer.GetD3DDeviceResources()->GetDeviceContext());
|
||||||
|
}
|
||||||
|
inline void ImGui_Impl_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_Shutdown();
|
||||||
|
}
|
||||||
|
inline void ImGui_Impl_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_NewFrame();
|
||||||
|
}
|
||||||
|
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_RenderDrawData(draw_data);
|
||||||
|
}
|
||||||
|
|
||||||
inline void ImGui_Impl_InvalidateDeviceObjects() { ImGui_ImplDX11_InvalidateDeviceObjects(); }
|
inline void ImGui_Impl_InvalidateDeviceObjects()
|
||||||
inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX11_CreateDeviceObjects(); }
|
{
|
||||||
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
}
|
||||||
|
inline bool ImGui_Impl_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
return ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <kiwano-imgui/imgui_impl_dx10.h>
|
#include <kiwano-imgui/imgui_impl_dx10.h>
|
||||||
|
|
||||||
inline bool ImGui_Impl_Init(::kiwano::Renderer* renderer) { return ImGui_ImplDX10_Init(renderer->GetD3DDeviceResources()->GetDevice()); }
|
inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer)
|
||||||
inline void ImGui_Impl_Shutdown() { ImGui_ImplDX10_Shutdown(); }
|
{
|
||||||
inline void ImGui_Impl_NewFrame() { ImGui_ImplDX10_NewFrame(); }
|
return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice());
|
||||||
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data) { ImGui_ImplDX10_RenderDrawData(draw_data); }
|
}
|
||||||
|
inline void ImGui_Impl_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX10_Shutdown();
|
||||||
|
}
|
||||||
|
inline void ImGui_Impl_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX10_NewFrame();
|
||||||
|
}
|
||||||
|
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX10_RenderDrawData(draw_data);
|
||||||
|
}
|
||||||
|
|
||||||
inline void ImGui_Impl_InvalidateDeviceObjects() { ImGui_ImplDX10_InvalidateDeviceObjects(); }
|
inline void ImGui_Impl_InvalidateDeviceObjects()
|
||||||
inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX10_CreateDeviceObjects(); }
|
{
|
||||||
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
|
}
|
||||||
|
inline bool ImGui_Impl_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
return ImGui_ImplDX10_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,40 +3,41 @@
|
||||||
#include <kiwano-imgui/imgui_impl_dx10.h>
|
#include <kiwano-imgui/imgui_impl_dx10.h>
|
||||||
|
|
||||||
// DirectX
|
// DirectX
|
||||||
#include <stdio.h>
|
|
||||||
#include <d3d10_1.h>
|
#include <d3d10_1.h>
|
||||||
#include <d3d10.h>
|
#include <d3d10.h>
|
||||||
#include <d3dcompiler.h>
|
#include <d3dcompiler.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static ID3D10Device* g_pd3dDevice = NULL;
|
static ID3D10Device* g_pd3dDevice = NULL;
|
||||||
static IDXGIFactory* g_pFactory = NULL;
|
static IDXGIFactory* g_pFactory = NULL;
|
||||||
static ID3D10Buffer* g_pVB = NULL;
|
static ID3D10Buffer* g_pVB = NULL;
|
||||||
static ID3D10Buffer* g_pIB = NULL;
|
static ID3D10Buffer* g_pIB = NULL;
|
||||||
static ID3D10Blob* g_pVertexShaderBlob = NULL;
|
static ID3D10Blob* g_pVertexShaderBlob = NULL;
|
||||||
static ID3D10VertexShader* g_pVertexShader = NULL;
|
static ID3D10VertexShader* g_pVertexShader = NULL;
|
||||||
static ID3D10InputLayout* g_pInputLayout = NULL;
|
static ID3D10InputLayout* g_pInputLayout = NULL;
|
||||||
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
|
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
|
||||||
static ID3D10Blob* g_pPixelShaderBlob = NULL;
|
static ID3D10Blob* g_pPixelShaderBlob = NULL;
|
||||||
static ID3D10PixelShader* g_pPixelShader = NULL;
|
static ID3D10PixelShader* g_pPixelShader = NULL;
|
||||||
static ID3D10SamplerState* g_pFontSampler = NULL;
|
static ID3D10SamplerState* g_pFontSampler = NULL;
|
||||||
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
|
static ID3D10ShaderResourceView* g_pFontTextureView = NULL;
|
||||||
static ID3D10RasterizerState* g_pRasterizerState = NULL;
|
static ID3D10RasterizerState* g_pRasterizerState = NULL;
|
||||||
static ID3D10BlendState* g_pBlendState = NULL;
|
static ID3D10BlendState* g_pBlendState = NULL;
|
||||||
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
|
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
struct VERTEX_CONSTANT_BUFFER
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render Function
|
// Render Function
|
||||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from
|
||||||
|
// your main loop)
|
||||||
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
{
|
{
|
||||||
ID3D10Device* ctx = g_pd3dDevice;
|
ID3D10Device* ctx = g_pd3dDevice;
|
||||||
|
|
@ -44,28 +45,36 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (g_pVB)
|
||||||
|
{
|
||||||
|
g_pVB->Release();
|
||||||
|
g_pVB = NULL;
|
||||||
|
}
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
||||||
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (g_pIB)
|
||||||
|
{
|
||||||
|
g_pIB->Release();
|
||||||
|
g_pIB = NULL;
|
||||||
|
}
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
@ -73,7 +82,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
|
||||||
// Copy and convert all vertices into a single contiguous buffer
|
// Copy and convert all vertices into a single contiguous buffer
|
||||||
ImDrawVert* vtx_dst = NULL;
|
ImDrawVert* vtx_dst = NULL;
|
||||||
ImDrawIdx* idx_dst = NULL;
|
ImDrawIdx* idx_dst = NULL;
|
||||||
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
||||||
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
|
@ -88,48 +97,49 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
g_pIB->Unmap();
|
g_pIB->Unmap();
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
|
||||||
|
// draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
{
|
{
|
||||||
void* mapped_resource;
|
void* mapped_resource;
|
||||||
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
|
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
float T = draw_data->DisplayPos.y;
|
float T = draw_data->DisplayPos.y;
|
||||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
float mvp[4][4] =
|
float mvp[4][4] = {
|
||||||
{
|
{ 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
|
||||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
{ 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
|
||||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
{ (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
|
||||||
};
|
};
|
||||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
g_pVertexConstantBuffer->Unmap();
|
g_pVertexConstantBuffer->Unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and
|
||||||
|
// verbose. Close your eyes!)
|
||||||
struct BACKUP_DX10_STATE
|
struct BACKUP_DX10_STATE
|
||||||
{
|
{
|
||||||
UINT ScissorRectsCount, ViewportsCount;
|
UINT ScissorRectsCount, ViewportsCount;
|
||||||
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
ID3D10RasterizerState* RS;
|
ID3D10RasterizerState* RS;
|
||||||
ID3D10BlendState* BlendState;
|
ID3D10BlendState* BlendState;
|
||||||
FLOAT BlendFactor[4];
|
FLOAT BlendFactor[4];
|
||||||
UINT SampleMask;
|
UINT SampleMask;
|
||||||
UINT StencilRef;
|
UINT StencilRef;
|
||||||
ID3D10DepthStencilState* DepthStencilState;
|
ID3D10DepthStencilState* DepthStencilState;
|
||||||
ID3D10ShaderResourceView* PSShaderResource;
|
ID3D10ShaderResourceView* PSShaderResource;
|
||||||
ID3D10SamplerState* PSSampler;
|
ID3D10SamplerState* PSSampler;
|
||||||
ID3D10PixelShader* PS;
|
ID3D10PixelShader* PS;
|
||||||
ID3D10VertexShader* VS;
|
ID3D10VertexShader* VS;
|
||||||
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||||
ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
ID3D10Buffer * IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||||
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||||
DXGI_FORMAT IndexBufferFormat;
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
ID3D10InputLayout* InputLayout;
|
ID3D10InputLayout* InputLayout;
|
||||||
};
|
};
|
||||||
BACKUP_DX10_STATE old;
|
BACKUP_DX10_STATE old;
|
||||||
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
|
|
@ -151,8 +161,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3D10_VIEWPORT vp;
|
D3D10_VIEWPORT vp;
|
||||||
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
||||||
vp.Width = (UINT)draw_data->DisplaySize.x;
|
vp.Width = (UINT)draw_data->DisplaySize.x;
|
||||||
vp.Height = (UINT)draw_data->DisplaySize.y;
|
vp.Height = (UINT)draw_data->DisplaySize.y;
|
||||||
vp.MinDepth = 0.0f;
|
vp.MinDepth = 0.0f;
|
||||||
vp.MaxDepth = 1.0f;
|
vp.MaxDepth = 1.0f;
|
||||||
vp.TopLeftX = vp.TopLeftY = 0;
|
vp.TopLeftX = vp.TopLeftY = 0;
|
||||||
|
|
@ -177,9 +187,9 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
ctx->RSSetState(g_pRasterizerState);
|
ctx->RSSetState(g_pRasterizerState);
|
||||||
|
|
||||||
// Render command lists
|
// Render command lists
|
||||||
int vtx_offset = 0;
|
int vtx_offset = 0;
|
||||||
int idx_offset = 0;
|
int idx_offset = 0;
|
||||||
ImVec2 pos = draw_data->DisplayPos;
|
ImVec2 pos = draw_data->DisplayPos;
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
{
|
{
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
@ -194,7 +204,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Apply scissor/clipping rectangle
|
// Apply scissor/clipping rectangle
|
||||||
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - pos.x), (LONG)(pcmd->ClipRect.y - pos.y), (LONG)(pcmd->ClipRect.z - pos.x), (LONG)(pcmd->ClipRect.w - pos.y)};
|
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - pos.x), (LONG)(pcmd->ClipRect.y - pos.y),
|
||||||
|
(LONG)(pcmd->ClipRect.z - pos.x), (LONG)(pcmd->ClipRect.w - pos.y) };
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
|
|
@ -210,55 +221,77 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
// Restore modified DX state
|
// Restore modified DX state
|
||||||
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||||
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||||
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
ctx->RSSetState(old.RS);
|
||||||
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
if (old.RS)
|
||||||
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
old.RS->Release();
|
||||||
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask);
|
||||||
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
if (old.BlendState)
|
||||||
ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release();
|
old.BlendState->Release();
|
||||||
ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release();
|
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef);
|
||||||
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
if (old.DepthStencilState)
|
||||||
|
old.DepthStencilState->Release();
|
||||||
|
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource);
|
||||||
|
if (old.PSShaderResource)
|
||||||
|
old.PSShaderResource->Release();
|
||||||
|
ctx->PSSetSamplers(0, 1, &old.PSSampler);
|
||||||
|
if (old.PSSampler)
|
||||||
|
old.PSSampler->Release();
|
||||||
|
ctx->PSSetShader(old.PS);
|
||||||
|
if (old.PS)
|
||||||
|
old.PS->Release();
|
||||||
|
ctx->VSSetShader(old.VS);
|
||||||
|
if (old.VS)
|
||||||
|
old.VS->Release();
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||||
|
if (old.VSConstantBuffer)
|
||||||
|
old.VSConstantBuffer->Release();
|
||||||
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||||
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset);
|
||||||
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
if (old.IndexBuffer)
|
||||||
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
old.IndexBuffer->Release();
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||||
|
if (old.VertexBuffer)
|
||||||
|
old.VertexBuffer->Release();
|
||||||
|
ctx->IASetInputLayout(old.InputLayout);
|
||||||
|
if (old.InputLayout)
|
||||||
|
old.InputLayout->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX10_CreateFontsTexture()
|
static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
// Upload texture to graphics system
|
// Upload texture to graphics system
|
||||||
{
|
{
|
||||||
D3D10_TEXTURE2D_DESC desc;
|
D3D10_TEXTURE2D_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.Width = width;
|
desc.Width = width;
|
||||||
desc.Height = height;
|
desc.Height = height;
|
||||||
desc.MipLevels = 1;
|
desc.MipLevels = 1;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Usage = D3D10_USAGE_DEFAULT;
|
desc.Usage = D3D10_USAGE_DEFAULT;
|
||||||
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||||
desc.CPUAccessFlags = 0;
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
ID3D10Texture2D *pTexture = NULL;
|
ID3D10Texture2D* pTexture = NULL;
|
||||||
D3D10_SUBRESOURCE_DATA subResource;
|
D3D10_SUBRESOURCE_DATA subResource;
|
||||||
subResource.pSysMem = pixels;
|
subResource.pSysMem = pixels;
|
||||||
subResource.SysMemPitch = desc.Width * 4;
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
subResource.SysMemSlicePitch = 0;
|
subResource.SysMemSlicePitch = 0;
|
||||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
// Create texture view
|
// Create texture view
|
||||||
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||||
ZeroMemory(&srv_desc, sizeof(srv_desc));
|
ZeroMemory(&srv_desc, sizeof(srv_desc));
|
||||||
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||||
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
|
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
|
||||||
pTexture->Release();
|
pTexture->Release();
|
||||||
|
|
@ -271,35 +304,36 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
D3D10_SAMPLER_DESC desc;
|
D3D10_SAMPLER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
|
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
|
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||||
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
|
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||||
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
|
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||||
desc.MipLODBias = 0.f;
|
desc.MipLODBias = 0.f;
|
||||||
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.MinLOD = 0.f;
|
desc.MinLOD = 0.f;
|
||||||
desc.MaxLOD = 0.f;
|
desc.MaxLOD = 0.f;
|
||||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_CreateDeviceObjects()
|
bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
if (!g_pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pFontSampler)
|
if (g_pFontSampler)
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
|
|
||||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of
|
||||||
// If you would like to use this DX10 sample code but remove this dependency you can:
|
// d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) If you would like to use this DX10 sample code but remove this
|
||||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
// dependency you can:
|
||||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to
|
||||||
|
// CreateVertexShader()/CreatePixelShader() [preferred solution] 2) use code to detect any version of the DLL and
|
||||||
|
// grab a pointer to D3DCompile from the DLL.
|
||||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
// Create the vertex shader
|
// Create the vertex shader
|
||||||
{
|
{
|
||||||
static const char* vertexShader =
|
static const char* vertexShader = "cbuffer vertexBuffer : register(b0) \
|
||||||
"cbuffer vertexBuffer : register(b0) \
|
|
||||||
{\
|
{\
|
||||||
float4x4 ProjectionMatrix; \
|
float4x4 ProjectionMatrix; \
|
||||||
};\
|
};\
|
||||||
|
|
@ -326,38 +360,46 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
return output;\
|
return output;\
|
||||||
}";
|
}";
|
||||||
|
|
||||||
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL);
|
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob,
|
||||||
if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
NULL);
|
||||||
|
if (g_pVertexShaderBlob
|
||||||
|
== NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const
|
||||||
|
// char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
return false;
|
return false;
|
||||||
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pVertexShader) != S_OK)
|
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(),
|
||||||
|
g_pVertexShaderBlob->GetBufferSize(), &g_pVertexShader)
|
||||||
|
!= S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the input layout
|
// Create the input layout
|
||||||
D3D10_INPUT_ELEMENT_DESC local_layout[] =
|
D3D10_INPUT_ELEMENT_DESC local_layout[] = {
|
||||||
{
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA,
|
||||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
0 },
|
||||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA,
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D10_INPUT_PER_VERTEX_DATA,
|
||||||
|
0 },
|
||||||
};
|
};
|
||||||
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(),
|
||||||
|
g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout)
|
||||||
|
!= S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the constant buffer
|
// Create the constant buffer
|
||||||
{
|
{
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the pixel shader
|
// Create the pixel shader
|
||||||
{
|
{
|
||||||
static const char* pixelShader =
|
static const char* pixelShader = "struct PS_INPUT\
|
||||||
"struct PS_INPUT\
|
|
||||||
{\
|
{\
|
||||||
float4 pos : SV_POSITION;\
|
float4 pos : SV_POSITION;\
|
||||||
float4 col : COLOR0;\
|
float4 col : COLOR0;\
|
||||||
|
|
@ -372,10 +414,15 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
return out_col; \
|
return out_col; \
|
||||||
}";
|
}";
|
||||||
|
|
||||||
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL);
|
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob,
|
||||||
if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
NULL);
|
||||||
|
if (g_pPixelShaderBlob
|
||||||
|
== NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const
|
||||||
|
// char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
return false;
|
return false;
|
||||||
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), &g_pPixelShader) != S_OK)
|
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(),
|
||||||
|
g_pPixelShaderBlob->GetBufferSize(), &g_pPixelShader)
|
||||||
|
!= S_OK)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -383,14 +430,14 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
D3D10_BLEND_DESC desc;
|
D3D10_BLEND_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.AlphaToCoverageEnable = false;
|
desc.AlphaToCoverageEnable = false;
|
||||||
desc.BlendEnable[0] = true;
|
desc.BlendEnable[0] = true;
|
||||||
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
||||||
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
desc.BlendOp = D3D10_BLEND_OP_ADD;
|
desc.BlendOp = D3D10_BLEND_OP_ADD;
|
||||||
desc.SrcBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
desc.SrcBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
desc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
desc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
||||||
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
||||||
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
||||||
}
|
}
|
||||||
|
|
@ -399,9 +446,9 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
D3D10_RASTERIZER_DESC desc;
|
D3D10_RASTERIZER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.FillMode = D3D10_FILL_SOLID;
|
desc.FillMode = D3D10_FILL_SOLID;
|
||||||
desc.CullMode = D3D10_CULL_NONE;
|
desc.CullMode = D3D10_CULL_NONE;
|
||||||
desc.ScissorEnable = true;
|
desc.ScissorEnable = true;
|
||||||
desc.DepthClipEnable = true;
|
desc.DepthClipEnable = true;
|
||||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
@ -410,13 +457,14 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
D3D10_DEPTH_STENCIL_DESC desc;
|
D3D10_DEPTH_STENCIL_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.DepthEnable = false;
|
desc.DepthEnable = false;
|
||||||
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
|
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
|
||||||
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
|
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.StencilEnable = false;
|
desc.StencilEnable = false;
|
||||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp =
|
||||||
|
D3D10_STENCIL_OP_KEEP;
|
||||||
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,46 +473,101 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
if (!g_pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
if (g_pFontSampler)
|
||||||
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
g_pFontSampler->Release();
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
g_pFontSampler = NULL;
|
||||||
|
}
|
||||||
|
if (g_pFontTextureView)
|
||||||
|
{
|
||||||
|
g_pFontTextureView->Release();
|
||||||
|
g_pFontTextureView = NULL;
|
||||||
|
ImGui::GetIO().Fonts->TexID = NULL;
|
||||||
|
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
if (g_pIB)
|
||||||
|
{
|
||||||
|
g_pIB->Release();
|
||||||
|
g_pIB = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVB)
|
||||||
|
{
|
||||||
|
g_pVB->Release();
|
||||||
|
g_pVB = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
if (g_pBlendState)
|
||||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
{
|
||||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
g_pBlendState->Release();
|
||||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
g_pBlendState = NULL;
|
||||||
if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
|
}
|
||||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
if (g_pDepthStencilState)
|
||||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
{
|
||||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
g_pDepthStencilState->Release();
|
||||||
if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
|
g_pDepthStencilState = NULL;
|
||||||
|
}
|
||||||
|
if (g_pRasterizerState)
|
||||||
|
{
|
||||||
|
g_pRasterizerState->Release();
|
||||||
|
g_pRasterizerState = NULL;
|
||||||
|
}
|
||||||
|
if (g_pPixelShader)
|
||||||
|
{
|
||||||
|
g_pPixelShader->Release();
|
||||||
|
g_pPixelShader = NULL;
|
||||||
|
}
|
||||||
|
if (g_pPixelShaderBlob)
|
||||||
|
{
|
||||||
|
g_pPixelShaderBlob->Release();
|
||||||
|
g_pPixelShaderBlob = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVertexConstantBuffer)
|
||||||
|
{
|
||||||
|
g_pVertexConstantBuffer->Release();
|
||||||
|
g_pVertexConstantBuffer = NULL;
|
||||||
|
}
|
||||||
|
if (g_pInputLayout)
|
||||||
|
{
|
||||||
|
g_pInputLayout->Release();
|
||||||
|
g_pInputLayout = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVertexShader)
|
||||||
|
{
|
||||||
|
g_pVertexShader->Release();
|
||||||
|
g_pVertexShader = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVertexShaderBlob)
|
||||||
|
{
|
||||||
|
g_pVertexShaderBlob->Release();
|
||||||
|
g_pVertexShaderBlob = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.BackendRendererName = "imgui_impl_dx10";
|
io.BackendRendererName = "imgui_impl_dx10";
|
||||||
|
|
||||||
// Get factory from device
|
// Get factory from device
|
||||||
IDXGIDevice* pDXGIDevice = NULL;
|
IDXGIDevice* pDXGIDevice = NULL;
|
||||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||||
IDXGIFactory* pFactory = NULL;
|
IDXGIFactory* pFactory = NULL;
|
||||||
|
|
||||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
{
|
{
|
||||||
g_pd3dDevice = device;
|
g_pd3dDevice = device;
|
||||||
g_pFactory = pFactory;
|
g_pFactory = pFactory;
|
||||||
}
|
}
|
||||||
if (pDXGIDevice) pDXGIDevice->Release();
|
if (pDXGIDevice)
|
||||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
pDXGIDevice->Release();
|
||||||
|
if (pDXGIAdapter)
|
||||||
|
pDXGIAdapter->Release();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -472,7 +575,11 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
void ImGui_ImplDX10_Shutdown()
|
void ImGui_ImplDX10_Shutdown()
|
||||||
{
|
{
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
if (g_pFactory)
|
||||||
|
{
|
||||||
|
g_pFactory->Release();
|
||||||
|
g_pFactory = NULL;
|
||||||
|
}
|
||||||
g_pd3dDevice = NULL;
|
g_pd3dDevice = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
struct ID3D10Device;
|
struct ID3D10Device;
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
|
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
|
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
|
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
|
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
// Use if you want to reset your rendering device without losing ImGui state.
|
// Use if you want to reset your rendering device without losing ImGui state.
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
|
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
|
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -3,40 +3,41 @@
|
||||||
#include <kiwano-imgui/imgui_impl_dx11.h>
|
#include <kiwano-imgui/imgui_impl_dx11.h>
|
||||||
|
|
||||||
// DirectX
|
// DirectX
|
||||||
#include <stdio.h>
|
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include <d3dcompiler.h>
|
#include <d3dcompiler.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static ID3D11Device* g_pd3dDevice = NULL;
|
static ID3D11Device* g_pd3dDevice = NULL;
|
||||||
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
||||||
static IDXGIFactory* g_pFactory = NULL;
|
static IDXGIFactory* g_pFactory = NULL;
|
||||||
static ID3D11Buffer* g_pVB = NULL;
|
static ID3D11Buffer* g_pVB = NULL;
|
||||||
static ID3D11Buffer* g_pIB = NULL;
|
static ID3D11Buffer* g_pIB = NULL;
|
||||||
static ID3D10Blob* g_pVertexShaderBlob = NULL;
|
static ID3D10Blob* g_pVertexShaderBlob = NULL;
|
||||||
static ID3D11VertexShader* g_pVertexShader = NULL;
|
static ID3D11VertexShader* g_pVertexShader = NULL;
|
||||||
static ID3D11InputLayout* g_pInputLayout = NULL;
|
static ID3D11InputLayout* g_pInputLayout = NULL;
|
||||||
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
||||||
static ID3D10Blob* g_pPixelShaderBlob = NULL;
|
static ID3D10Blob* g_pPixelShaderBlob = NULL;
|
||||||
static ID3D11PixelShader* g_pPixelShader = NULL;
|
static ID3D11PixelShader* g_pPixelShader = NULL;
|
||||||
static ID3D11SamplerState* g_pFontSampler = NULL;
|
static ID3D11SamplerState* g_pFontSampler = NULL;
|
||||||
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
|
static ID3D11ShaderResourceView* g_pFontTextureView = NULL;
|
||||||
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
||||||
static ID3D11BlendState* g_pBlendState = NULL;
|
static ID3D11BlendState* g_pBlendState = NULL;
|
||||||
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
struct VERTEX_CONSTANT_BUFFER
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render Function
|
// Render Function
|
||||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from
|
||||||
|
// your main loop)
|
||||||
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
{
|
{
|
||||||
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
||||||
|
|
@ -44,27 +45,35 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (g_pVB)
|
||||||
|
{
|
||||||
|
g_pVB->Release();
|
||||||
|
g_pVB = NULL;
|
||||||
|
}
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
||||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (g_pIB)
|
||||||
|
{
|
||||||
|
g_pIB->Release();
|
||||||
|
g_pIB = NULL;
|
||||||
|
}
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
@ -77,7 +86,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||||
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
{
|
{
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
@ -90,50 +99,51 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
ctx->Unmap(g_pIB, 0);
|
ctx->Unmap(g_pIB, 0);
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
|
||||||
|
// draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
{
|
{
|
||||||
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||||
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
float T = draw_data->DisplayPos.y;
|
float T = draw_data->DisplayPos.y;
|
||||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
float mvp[4][4] =
|
float mvp[4][4] = {
|
||||||
{
|
{ 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
|
||||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
{ 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
|
||||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
{ (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
|
||||||
};
|
};
|
||||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and
|
||||||
|
// verbose. Close your eyes!)
|
||||||
struct BACKUP_DX11_STATE
|
struct BACKUP_DX11_STATE
|
||||||
{
|
{
|
||||||
UINT ScissorRectsCount, ViewportsCount;
|
UINT ScissorRectsCount, ViewportsCount;
|
||||||
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
ID3D11RasterizerState* RS;
|
ID3D11RasterizerState* RS;
|
||||||
ID3D11BlendState* BlendState;
|
ID3D11BlendState* BlendState;
|
||||||
FLOAT BlendFactor[4];
|
FLOAT BlendFactor[4];
|
||||||
UINT SampleMask;
|
UINT SampleMask;
|
||||||
UINT StencilRef;
|
UINT StencilRef;
|
||||||
ID3D11DepthStencilState* DepthStencilState;
|
ID3D11DepthStencilState* DepthStencilState;
|
||||||
ID3D11ShaderResourceView* PSShaderResource;
|
ID3D11ShaderResourceView* PSShaderResource;
|
||||||
ID3D11SamplerState* PSSampler;
|
ID3D11SamplerState* PSSampler;
|
||||||
ID3D11PixelShader* PS;
|
ID3D11PixelShader* PS;
|
||||||
ID3D11VertexShader* VS;
|
ID3D11VertexShader* VS;
|
||||||
UINT PSInstancesCount, VSInstancesCount;
|
UINT PSInstancesCount, VSInstancesCount;
|
||||||
ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
|
ID3D11ClassInstance *PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
|
||||||
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||||
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
ID3D11Buffer * IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||||
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||||
DXGI_FORMAT IndexBufferFormat;
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
ID3D11InputLayout* InputLayout;
|
ID3D11InputLayout* InputLayout;
|
||||||
};
|
};
|
||||||
BACKUP_DX11_STATE old;
|
BACKUP_DX11_STATE old;
|
||||||
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
|
|
@ -156,8 +166,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3D11_VIEWPORT vp;
|
D3D11_VIEWPORT vp;
|
||||||
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||||
vp.Width = draw_data->DisplaySize.x;
|
vp.Width = draw_data->DisplaySize.x;
|
||||||
vp.Height = draw_data->DisplaySize.y;
|
vp.Height = draw_data->DisplaySize.y;
|
||||||
vp.MinDepth = 0.0f;
|
vp.MinDepth = 0.0f;
|
||||||
vp.MaxDepth = 1.0f;
|
vp.MaxDepth = 1.0f;
|
||||||
vp.TopLeftX = vp.TopLeftY = 0;
|
vp.TopLeftX = vp.TopLeftY = 0;
|
||||||
|
|
@ -182,9 +192,9 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
ctx->RSSetState(g_pRasterizerState);
|
ctx->RSSetState(g_pRasterizerState);
|
||||||
|
|
||||||
// Render command lists
|
// Render command lists
|
||||||
int vtx_offset = 0;
|
int vtx_offset = 0;
|
||||||
int idx_offset = 0;
|
int idx_offset = 0;
|
||||||
ImVec2 pos = draw_data->DisplayPos;
|
ImVec2 pos = draw_data->DisplayPos;
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
{
|
{
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
@ -199,7 +209,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Apply scissor/clipping rectangle
|
// Apply scissor/clipping rectangle
|
||||||
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - pos.x), (LONG)(pcmd->ClipRect.y - pos.y), (LONG)(pcmd->ClipRect.z - pos.x), (LONG)(pcmd->ClipRect.w - pos.y) };
|
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - pos.x), (LONG)(pcmd->ClipRect.y - pos.y),
|
||||||
|
(LONG)(pcmd->ClipRect.z - pos.x), (LONG)(pcmd->ClipRect.w - pos.y) };
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
|
|
@ -215,61 +226,87 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
// Restore modified DX state
|
// Restore modified DX state
|
||||||
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||||
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||||
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
ctx->RSSetState(old.RS);
|
||||||
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
if (old.RS)
|
||||||
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
old.RS->Release();
|
||||||
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask);
|
||||||
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
if (old.BlendState)
|
||||||
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
|
old.BlendState->Release();
|
||||||
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
|
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef);
|
||||||
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
|
if (old.DepthStencilState)
|
||||||
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
old.DepthStencilState->Release();
|
||||||
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
|
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource);
|
||||||
|
if (old.PSShaderResource)
|
||||||
|
old.PSShaderResource->Release();
|
||||||
|
ctx->PSSetSamplers(0, 1, &old.PSSampler);
|
||||||
|
if (old.PSSampler)
|
||||||
|
old.PSSampler->Release();
|
||||||
|
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount);
|
||||||
|
if (old.PS)
|
||||||
|
old.PS->Release();
|
||||||
|
for (UINT i = 0; i < old.PSInstancesCount; i++)
|
||||||
|
if (old.PSInstances[i])
|
||||||
|
old.PSInstances[i]->Release();
|
||||||
|
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount);
|
||||||
|
if (old.VS)
|
||||||
|
old.VS->Release();
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||||
|
if (old.VSConstantBuffer)
|
||||||
|
old.VSConstantBuffer->Release();
|
||||||
|
for (UINT i = 0; i < old.VSInstancesCount; i++)
|
||||||
|
if (old.VSInstances[i])
|
||||||
|
old.VSInstances[i]->Release();
|
||||||
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||||
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset);
|
||||||
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
if (old.IndexBuffer)
|
||||||
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
old.IndexBuffer->Release();
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||||
|
if (old.VertexBuffer)
|
||||||
|
old.VertexBuffer->Release();
|
||||||
|
ctx->IASetInputLayout(old.InputLayout);
|
||||||
|
if (old.InputLayout)
|
||||||
|
old.InputLayout->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplDX11_CreateFontsTexture()
|
static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
// Upload texture to graphics system
|
// Upload texture to graphics system
|
||||||
{
|
{
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.Width = width;
|
desc.Width = width;
|
||||||
desc.Height = height;
|
desc.Height = height;
|
||||||
desc.MipLevels = 1;
|
desc.MipLevels = 1;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
desc.CPUAccessFlags = 0;
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
ID3D11Texture2D *pTexture = NULL;
|
ID3D11Texture2D* pTexture = NULL;
|
||||||
D3D11_SUBRESOURCE_DATA subResource;
|
D3D11_SUBRESOURCE_DATA subResource;
|
||||||
subResource.pSysMem = pixels;
|
subResource.pSysMem = pixels;
|
||||||
subResource.SysMemPitch = desc.Width * 4;
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
subResource.SysMemSlicePitch = 0;
|
subResource.SysMemSlicePitch = 0;
|
||||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
if (pTexture)
|
if (pTexture)
|
||||||
{
|
{
|
||||||
// Create texture view
|
// Create texture view
|
||||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
|
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
|
||||||
|
|
||||||
pTexture->Release();
|
pTexture->Release();
|
||||||
}
|
}
|
||||||
|
|
@ -282,35 +319,36 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
D3D11_SAMPLER_DESC desc;
|
D3D11_SAMPLER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
desc.MipLODBias = 0.f;
|
desc.MipLODBias = 0.f;
|
||||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.MinLOD = 0.f;
|
desc.MinLOD = 0.f;
|
||||||
desc.MaxLOD = 0.f;
|
desc.MaxLOD = 0.f;
|
||||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_CreateDeviceObjects()
|
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
if (!g_pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pFontSampler)
|
if (g_pFontSampler)
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
|
||||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of
|
||||||
// If you would like to use this DX11 sample code but remove this dependency you can:
|
// d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) If you would like to use this DX11 sample code but remove this
|
||||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
// dependency you can:
|
||||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to
|
||||||
|
// CreateVertexShader()/CreatePixelShader() [preferred solution] 2) use code to detect any version of the DLL and
|
||||||
|
// grab a pointer to D3DCompile from the DLL.
|
||||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
// Create the vertex shader
|
// Create the vertex shader
|
||||||
{
|
{
|
||||||
static const char* vertexShader =
|
static const char* vertexShader = "cbuffer vertexBuffer : register(b0) \
|
||||||
"cbuffer vertexBuffer : register(b0) \
|
|
||||||
{\
|
{\
|
||||||
float4x4 ProjectionMatrix; \
|
float4x4 ProjectionMatrix; \
|
||||||
};\
|
};\
|
||||||
|
|
@ -337,38 +375,46 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
return output;\
|
return output;\
|
||||||
}";
|
}";
|
||||||
|
|
||||||
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL);
|
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob,
|
||||||
if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
NULL);
|
||||||
|
if (g_pVertexShaderBlob
|
||||||
|
== NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const
|
||||||
|
// char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
return false;
|
return false;
|
||||||
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
|
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(),
|
||||||
|
g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader)
|
||||||
|
!= S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the input layout
|
// Create the input layout
|
||||||
D3D11_INPUT_ELEMENT_DESC local_layout[] =
|
D3D11_INPUT_ELEMENT_DESC local_layout[] = {
|
||||||
{
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA,
|
||||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
0 },
|
||||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA,
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA,
|
||||||
|
0 },
|
||||||
};
|
};
|
||||||
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(),
|
||||||
|
g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout)
|
||||||
|
!= S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the constant buffer
|
// Create the constant buffer
|
||||||
{
|
{
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the pixel shader
|
// Create the pixel shader
|
||||||
{
|
{
|
||||||
static const char* pixelShader =
|
static const char* pixelShader = "struct PS_INPUT\
|
||||||
"struct PS_INPUT\
|
|
||||||
{\
|
{\
|
||||||
float4 pos : SV_POSITION;\
|
float4 pos : SV_POSITION;\
|
||||||
float4 col : COLOR0;\
|
float4 col : COLOR0;\
|
||||||
|
|
@ -383,10 +429,15 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
return out_col; \
|
return out_col; \
|
||||||
}";
|
}";
|
||||||
|
|
||||||
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL);
|
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob,
|
||||||
if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
NULL);
|
||||||
|
if (g_pPixelShaderBlob
|
||||||
|
== NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const
|
||||||
|
// char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
return false;
|
return false;
|
||||||
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
|
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(),
|
||||||
|
g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader)
|
||||||
|
!= S_OK)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,14 +445,14 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
D3D11_BLEND_DESC desc;
|
D3D11_BLEND_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.AlphaToCoverageEnable = false;
|
desc.AlphaToCoverageEnable = false;
|
||||||
desc.RenderTarget[0].BlendEnable = true;
|
desc.RenderTarget[0].BlendEnable = true;
|
||||||
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||||
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
||||||
}
|
}
|
||||||
|
|
@ -410,9 +461,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
D3D11_RASTERIZER_DESC desc;
|
D3D11_RASTERIZER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.FillMode = D3D11_FILL_SOLID;
|
desc.FillMode = D3D11_FILL_SOLID;
|
||||||
desc.CullMode = D3D11_CULL_NONE;
|
desc.CullMode = D3D11_CULL_NONE;
|
||||||
desc.ScissorEnable = true;
|
desc.ScissorEnable = true;
|
||||||
desc.DepthClipEnable = true;
|
desc.DepthClipEnable = true;
|
||||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
@ -421,13 +472,14 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
D3D11_DEPTH_STENCIL_DESC desc;
|
D3D11_DEPTH_STENCIL_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
desc.DepthEnable = false;
|
desc.DepthEnable = false;
|
||||||
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||||
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.StencilEnable = false;
|
desc.StencilEnable = false;
|
||||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp =
|
||||||
|
D3D11_STENCIL_OP_KEEP;
|
||||||
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -436,47 +488,102 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
if (!g_pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
if (g_pFontSampler)
|
||||||
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
g_pFontSampler->Release();
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
g_pFontSampler = NULL;
|
||||||
|
}
|
||||||
|
if (g_pFontTextureView)
|
||||||
|
{
|
||||||
|
g_pFontTextureView->Release();
|
||||||
|
g_pFontTextureView = NULL;
|
||||||
|
ImGui::GetIO().Fonts->TexID = NULL;
|
||||||
|
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
if (g_pIB)
|
||||||
|
{
|
||||||
|
g_pIB->Release();
|
||||||
|
g_pIB = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVB)
|
||||||
|
{
|
||||||
|
g_pVB->Release();
|
||||||
|
g_pVB = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
if (g_pBlendState)
|
||||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
{
|
||||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
g_pBlendState->Release();
|
||||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
g_pBlendState = NULL;
|
||||||
if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
|
}
|
||||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
if (g_pDepthStencilState)
|
||||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
{
|
||||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
g_pDepthStencilState->Release();
|
||||||
if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
|
g_pDepthStencilState = NULL;
|
||||||
|
}
|
||||||
|
if (g_pRasterizerState)
|
||||||
|
{
|
||||||
|
g_pRasterizerState->Release();
|
||||||
|
g_pRasterizerState = NULL;
|
||||||
|
}
|
||||||
|
if (g_pPixelShader)
|
||||||
|
{
|
||||||
|
g_pPixelShader->Release();
|
||||||
|
g_pPixelShader = NULL;
|
||||||
|
}
|
||||||
|
if (g_pPixelShaderBlob)
|
||||||
|
{
|
||||||
|
g_pPixelShaderBlob->Release();
|
||||||
|
g_pPixelShaderBlob = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVertexConstantBuffer)
|
||||||
|
{
|
||||||
|
g_pVertexConstantBuffer->Release();
|
||||||
|
g_pVertexConstantBuffer = NULL;
|
||||||
|
}
|
||||||
|
if (g_pInputLayout)
|
||||||
|
{
|
||||||
|
g_pInputLayout->Release();
|
||||||
|
g_pInputLayout = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVertexShader)
|
||||||
|
{
|
||||||
|
g_pVertexShader->Release();
|
||||||
|
g_pVertexShader = NULL;
|
||||||
|
}
|
||||||
|
if (g_pVertexShaderBlob)
|
||||||
|
{
|
||||||
|
g_pVertexShaderBlob->Release();
|
||||||
|
g_pVertexShaderBlob = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.BackendRendererName = "imgui_impl_dx11";
|
io.BackendRendererName = "imgui_impl_dx11";
|
||||||
|
|
||||||
// Get factory from device
|
// Get factory from device
|
||||||
IDXGIDevice* pDXGIDevice = NULL;
|
IDXGIDevice* pDXGIDevice = NULL;
|
||||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||||
IDXGIFactory* pFactory = NULL;
|
IDXGIFactory* pFactory = NULL;
|
||||||
|
|
||||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
{
|
{
|
||||||
g_pd3dDevice = device;
|
g_pd3dDevice = device;
|
||||||
g_pd3dDeviceContext = device_context;
|
g_pd3dDeviceContext = device_context;
|
||||||
g_pFactory = pFactory;
|
g_pFactory = pFactory;
|
||||||
}
|
}
|
||||||
if (pDXGIDevice) pDXGIDevice->Release();
|
if (pDXGIDevice)
|
||||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
pDXGIDevice->Release();
|
||||||
|
if (pDXGIAdapter)
|
||||||
|
pDXGIAdapter->Release();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -484,8 +591,12 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
|
||||||
void ImGui_ImplDX11_Shutdown()
|
void ImGui_ImplDX11_Shutdown()
|
||||||
{
|
{
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
if (g_pFactory)
|
||||||
g_pd3dDevice = NULL;
|
{
|
||||||
|
g_pFactory->Release();
|
||||||
|
g_pFactory = NULL;
|
||||||
|
}
|
||||||
|
g_pd3dDevice = NULL;
|
||||||
g_pd3dDeviceContext = NULL;
|
g_pd3dDeviceContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@
|
||||||
struct ID3D11Device;
|
struct ID3D11Device;
|
||||||
struct ID3D11DeviceContext;
|
struct ID3D11DeviceContext;
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
// Use if you want to reset your rendering device without losing ImGui state.
|
// Use if you want to reset your rendering device without losing ImGui state.
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -18,364 +18,338 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
|
#include <thread>
|
||||||
|
#include <kiwano/core/Logger.h>
|
||||||
|
#include <kiwano/platform/Application.h>
|
||||||
#include <kiwano-network/HttpRequest.h>
|
#include <kiwano-network/HttpRequest.h>
|
||||||
#include <kiwano-network/HttpResponse.hpp>
|
#include <kiwano-network/HttpResponse.hpp>
|
||||||
#include <kiwano-network/HttpClient.h>
|
#include <kiwano-network/HttpClient.h>
|
||||||
|
|
||||||
#include <kiwano/core/Logger.h>
|
|
||||||
#include <kiwano/platform/Application.h>
|
|
||||||
#include <3rd-party/curl/curl.h> // CURL
|
#include <3rd-party/curl/curl.h> // CURL
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using namespace kiwano;
|
using namespace kiwano;
|
||||||
using namespace kiwano::network;
|
using namespace kiwano::network;
|
||||||
|
|
||||||
uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp)
|
uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp)
|
||||||
{
|
{
|
||||||
ByteString* recv_buffer = (ByteString*)userp;
|
ByteString* recv_buffer = (ByteString*)userp;
|
||||||
uint32_t total = size * nmemb;
|
uint32_t total = size * nmemb;
|
||||||
|
|
||||||
// add data to the end of recv_buffer
|
// add data to the end of recv_buffer
|
||||||
// write data maybe called more than once in a single request
|
// write data maybe called more than once in a single request
|
||||||
recv_buffer->append((char*)buffer, total);
|
recv_buffer->append((char*)buffer, total);
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
|
||||||
|
|
||||||
ByteString convert_to_utf8(String const& str)
|
|
||||||
{
|
|
||||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
|
||||||
ByteString result;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = utf8_conv.to_bytes(str.c_str());
|
|
||||||
}
|
|
||||||
catch (std::range_error&)
|
|
||||||
{
|
|
||||||
// bad conversion
|
|
||||||
result = WideToMultiByte(str);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
String convert_from_utf8(ByteString const& str)
|
|
||||||
{
|
|
||||||
oc::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
|
||||||
String result;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = utf8_conv.from_bytes(str);
|
|
||||||
}
|
|
||||||
catch (std::range_error&)
|
|
||||||
{
|
|
||||||
// bad conversion
|
|
||||||
result = MultiByteToWide(str);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Curl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Curl()
|
|
||||||
: curl_(curl_easy_init())
|
|
||||||
, curl_headers_(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Curl()
|
|
||||||
{
|
|
||||||
if (curl_)
|
|
||||||
{
|
|
||||||
curl_easy_cleanup(curl_);
|
|
||||||
curl_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curl_headers_)
|
|
||||||
{
|
|
||||||
curl_slist_free_all(curl_headers_);
|
|
||||||
curl_headers_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
if (!SetOption(CURLOPT_TIMEOUT, client->GetTimeoutForRead()))
|
|
||||||
return false;
|
|
||||||
if (!SetOption(CURLOPT_CONNECTTIMEOUT, client->GetTimeoutForConnect()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto ssl_ca_file = wide_to_string(client->GetSSLVerification());
|
|
||||||
if (ssl_ca_file.empty()) {
|
|
||||||
if (!SetOption(CURLOPT_SSL_VERIFYPEER, 0L))
|
|
||||||
return false;
|
|
||||||
if (!SetOption(CURLOPT_SSL_VERIFYHOST, 0L))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!SetOption(CURLOPT_SSL_VERIFYPEER, 1L))
|
|
||||||
return false;
|
|
||||||
if (!SetOption(CURLOPT_SSL_VERIFYHOST, 2L))
|
|
||||||
return false;
|
|
||||||
if (!SetOption(CURLOPT_CAINFO, ssl_ca_file.c_str()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetOption(CURLOPT_NOSIGNAL, 1L))
|
|
||||||
return false;
|
|
||||||
if (!SetOption(CURLOPT_ACCEPT_ENCODING, ""))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// set request headers
|
|
||||||
if (!headers.empty())
|
|
||||||
{
|
|
||||||
for (const auto& header : headers)
|
|
||||||
{
|
|
||||||
curl_headers_ = curl_slist_append(curl_headers_, header.c_str());
|
|
||||||
}
|
|
||||||
if (!SetOption(CURLOPT_HTTPHEADER, curl_headers_))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SetOption(CURLOPT_URL, url.c_str())
|
|
||||||
&& SetOption(CURLOPT_WRITEFUNCTION, write_data)
|
|
||||||
&& SetOption(CURLOPT_WRITEDATA, response_data)
|
|
||||||
&& SetOption(CURLOPT_HEADERFUNCTION, write_data)
|
|
||||||
&& SetOption(CURLOPT_HEADERDATA, response_header);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Perform(long* response_code)
|
|
||||||
{
|
|
||||||
if (CURLE_OK != curl_easy_perform(curl_))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CURLcode code = curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, response_code);
|
|
||||||
return code == CURLE_OK && (*response_code >= 200 && *response_code < 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ..._Args>
|
|
||||||
bool SetOption(CURLoption option, _Args&&... args)
|
|
||||||
{
|
|
||||||
return CURLE_OK == curl_easy_setopt(curl_, option, std::forward<_Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static inline bool GetRequest(
|
|
||||||
HttpClient* client,
|
|
||||||
Vector<ByteString> const& headers,
|
|
||||||
ByteString const& url,
|
|
||||||
long* response_code,
|
|
||||||
ByteString* response_data,
|
|
||||||
ByteString* response_header,
|
|
||||||
char* error_buffer)
|
|
||||||
{
|
|
||||||
Curl curl;
|
|
||||||
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
|
||||||
&& curl.SetOption(CURLOPT_FOLLOWLOCATION, true)
|
|
||||||
&& curl.Perform(response_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool PostRequest(
|
|
||||||
HttpClient* client,
|
|
||||||
Vector<ByteString> const& headers,
|
|
||||||
ByteString const& url,
|
|
||||||
ByteString const& request_data,
|
|
||||||
long* response_code,
|
|
||||||
ByteString* response_data,
|
|
||||||
ByteString* response_header,
|
|
||||||
char* error_buffer)
|
|
||||||
{
|
|
||||||
Curl curl;
|
|
||||||
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
|
||||||
&& curl.SetOption(CURLOPT_POST, 1)
|
|
||||||
&& curl.SetOption(CURLOPT_POSTFIELDS, request_data.c_str())
|
|
||||||
&& curl.SetOption(CURLOPT_POSTFIELDSIZE, request_data.size())
|
|
||||||
&& curl.Perform(response_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool PutRequest(
|
|
||||||
HttpClient* client,
|
|
||||||
Vector<ByteString> const& headers,
|
|
||||||
ByteString const& url,
|
|
||||||
ByteString const& request_data,
|
|
||||||
long* response_code,
|
|
||||||
ByteString* response_data,
|
|
||||||
ByteString* response_header,
|
|
||||||
char* error_buffer)
|
|
||||||
{
|
|
||||||
Curl curl;
|
|
||||||
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
|
||||||
&& curl.SetOption(CURLOPT_CUSTOMREQUEST, "PUT")
|
|
||||||
&& curl.SetOption(CURLOPT_POSTFIELDS, request_data.c_str())
|
|
||||||
&& curl.SetOption(CURLOPT_POSTFIELDSIZE, request_data.size())
|
|
||||||
&& curl.Perform(response_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool DeleteRequest(
|
|
||||||
HttpClient* client,
|
|
||||||
Vector<ByteString> const& headers,
|
|
||||||
ByteString const& url,
|
|
||||||
long* response_code,
|
|
||||||
ByteString* response_data,
|
|
||||||
ByteString* response_header,
|
|
||||||
char* error_buffer)
|
|
||||||
{
|
|
||||||
Curl curl;
|
|
||||||
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
|
||||||
&& curl.SetOption(CURLOPT_CUSTOMREQUEST, "DELETE")
|
|
||||||
&& curl.SetOption(CURLOPT_FOLLOWLOCATION, true)
|
|
||||||
&& curl.Perform(response_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CURL* curl_;
|
|
||||||
curl_slist* curl_headers_;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteString convert_to_utf8(String const& str)
|
||||||
|
{
|
||||||
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
||||||
|
ByteString result;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = utf8_conv.to_bytes(str.c_str());
|
||||||
|
}
|
||||||
|
catch (std::range_error&)
|
||||||
|
{
|
||||||
|
// bad conversion
|
||||||
|
result = WideToMultiByte(str);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String convert_from_utf8(ByteString const& str)
|
||||||
|
{
|
||||||
|
oc::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
|
||||||
|
String result;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = utf8_conv.from_bytes(str);
|
||||||
|
}
|
||||||
|
catch (std::range_error&)
|
||||||
|
{
|
||||||
|
// bad conversion
|
||||||
|
result = MultiByteToWide(str);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Curl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Curl()
|
||||||
|
: curl_(curl_easy_init())
|
||||||
|
, curl_headers_(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Curl()
|
||||||
|
{
|
||||||
|
if (curl_)
|
||||||
|
{
|
||||||
|
curl_easy_cleanup(curl_);
|
||||||
|
curl_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curl_headers_)
|
||||||
|
{
|
||||||
|
curl_slist_free_all(curl_headers_);
|
||||||
|
curl_headers_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (!SetOption(CURLOPT_TIMEOUT, client->GetTimeoutForRead()))
|
||||||
|
return false;
|
||||||
|
if (!SetOption(CURLOPT_CONNECTTIMEOUT, client->GetTimeoutForConnect()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto ssl_ca_file = wide_to_string(client->GetSSLVerification());
|
||||||
|
if (ssl_ca_file.empty())
|
||||||
|
{
|
||||||
|
if (!SetOption(CURLOPT_SSL_VERIFYPEER, 0L))
|
||||||
|
return false;
|
||||||
|
if (!SetOption(CURLOPT_SSL_VERIFYHOST, 0L))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!SetOption(CURLOPT_SSL_VERIFYPEER, 1L))
|
||||||
|
return false;
|
||||||
|
if (!SetOption(CURLOPT_SSL_VERIFYHOST, 2L))
|
||||||
|
return false;
|
||||||
|
if (!SetOption(CURLOPT_CAINFO, ssl_ca_file.c_str()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetOption(CURLOPT_NOSIGNAL, 1L))
|
||||||
|
return false;
|
||||||
|
if (!SetOption(CURLOPT_ACCEPT_ENCODING, ""))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// set request headers
|
||||||
|
if (!headers.empty())
|
||||||
|
{
|
||||||
|
for (const auto& header : headers)
|
||||||
|
{
|
||||||
|
curl_headers_ = curl_slist_append(curl_headers_, header.c_str());
|
||||||
|
}
|
||||||
|
if (!SetOption(CURLOPT_HTTPHEADER, curl_headers_))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SetOption(CURLOPT_URL, url.c_str()) && SetOption(CURLOPT_WRITEFUNCTION, write_data)
|
||||||
|
&& SetOption(CURLOPT_WRITEDATA, response_data) && SetOption(CURLOPT_HEADERFUNCTION, write_data)
|
||||||
|
&& SetOption(CURLOPT_HEADERDATA, response_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Perform(long* response_code)
|
||||||
|
{
|
||||||
|
if (CURLE_OK != curl_easy_perform(curl_))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CURLcode code = curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, response_code);
|
||||||
|
return code == CURLE_OK && (*response_code >= 200 && *response_code < 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... _Args>
|
||||||
|
bool SetOption(CURLoption option, _Args&&... args)
|
||||||
|
{
|
||||||
|
return CURLE_OK == curl_easy_setopt(curl_, option, std::forward<_Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static inline bool GetRequest(HttpClient* client, Vector<ByteString> const& headers, ByteString const& url,
|
||||||
|
long* response_code, ByteString* response_data, ByteString* response_header,
|
||||||
|
char* error_buffer)
|
||||||
|
{
|
||||||
|
Curl curl;
|
||||||
|
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
||||||
|
&& curl.SetOption(CURLOPT_FOLLOWLOCATION, true) && curl.Perform(response_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool PostRequest(HttpClient* client, Vector<ByteString> const& headers, ByteString const& url,
|
||||||
|
ByteString const& request_data, long* response_code, ByteString* response_data,
|
||||||
|
ByteString* response_header, char* error_buffer)
|
||||||
|
{
|
||||||
|
Curl curl;
|
||||||
|
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
||||||
|
&& curl.SetOption(CURLOPT_POST, 1) && curl.SetOption(CURLOPT_POSTFIELDS, request_data.c_str())
|
||||||
|
&& curl.SetOption(CURLOPT_POSTFIELDSIZE, request_data.size()) && curl.Perform(response_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool PutRequest(HttpClient* client, Vector<ByteString> const& headers, ByteString const& url,
|
||||||
|
ByteString const& request_data, long* response_code, ByteString* response_data,
|
||||||
|
ByteString* response_header, char* error_buffer)
|
||||||
|
{
|
||||||
|
Curl curl;
|
||||||
|
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
||||||
|
&& curl.SetOption(CURLOPT_CUSTOMREQUEST, "PUT")
|
||||||
|
&& curl.SetOption(CURLOPT_POSTFIELDS, request_data.c_str())
|
||||||
|
&& curl.SetOption(CURLOPT_POSTFIELDSIZE, request_data.size()) && curl.Perform(response_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool DeleteRequest(HttpClient* client, Vector<ByteString> const& headers, ByteString const& url,
|
||||||
|
long* response_code, ByteString* response_data, ByteString* response_header,
|
||||||
|
char* error_buffer)
|
||||||
|
{
|
||||||
|
Curl curl;
|
||||||
|
return curl.Init(client, headers, url, response_data, response_header, error_buffer)
|
||||||
|
&& curl.SetOption(CURLOPT_CUSTOMREQUEST, "DELETE") && curl.SetOption(CURLOPT_FOLLOWLOCATION, true)
|
||||||
|
&& curl.Perform(response_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CURL* curl_;
|
||||||
|
curl_slist* curl_headers_;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace network
|
namespace network
|
||||||
{
|
{
|
||||||
HttpClient::HttpClient()
|
HttpClient::HttpClient()
|
||||||
: timeout_for_connect_(30000 /* 30 seconds */)
|
: timeout_for_connect_(30000 /* 30 seconds */)
|
||||||
, timeout_for_read_(60000 /* 60 seconds */)
|
, timeout_for_read_(60000 /* 60 seconds */)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
void HttpClient::SetupComponent()
|
|
||||||
{
|
|
||||||
::curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
|
|
||||||
std::thread thread(Closure(this, &HttpClient::NetworkThread));
|
|
||||||
thread.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpClient::DestroyComponent()
|
|
||||||
{
|
|
||||||
::curl_global_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpClient::Send(HttpRequestPtr request)
|
|
||||||
{
|
|
||||||
if (!request)
|
|
||||||
return;
|
|
||||||
|
|
||||||
request_mutex_.lock();
|
|
||||||
request_queue_.push(request);
|
|
||||||
request_mutex_.unlock();
|
|
||||||
|
|
||||||
sleep_condition_.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpClient::NetworkThread()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
HttpRequestPtr request;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(request_mutex_);
|
|
||||||
while (request_queue_.empty())
|
|
||||||
{
|
|
||||||
sleep_condition_.wait(request_mutex_);
|
|
||||||
}
|
|
||||||
request = request_queue_.front();
|
|
||||||
request_queue_.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpResponsePtr response = new (std::nothrow) HttpResponse(request);
|
|
||||||
Perform(request, response);
|
|
||||||
|
|
||||||
response_mutex_.lock();
|
|
||||||
response_queue_.push(response);
|
|
||||||
response_mutex_.unlock();
|
|
||||||
|
|
||||||
Application::PreformInMainThread(Closure(this, &HttpClient::DispatchResponseCallback));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpClient::Perform(HttpRequestPtr request, HttpResponsePtr response)
|
|
||||||
{
|
|
||||||
bool ok = false;
|
|
||||||
long response_code = 0;
|
|
||||||
char error_message[256] = { 0 };
|
|
||||||
ByteString response_header;
|
|
||||||
ByteString response_data;
|
|
||||||
|
|
||||||
ByteString url = convert_to_utf8(request->GetUrl());
|
|
||||||
ByteString data = convert_to_utf8(request->GetData());
|
|
||||||
|
|
||||||
Vector<ByteString> headers;
|
|
||||||
headers.reserve(request->GetHeaders().size());
|
|
||||||
for (const auto& pair : request->GetHeaders())
|
|
||||||
{
|
|
||||||
headers.push_back(wide_to_string(pair.first) + ":" + wide_to_string(pair.second));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (request->GetType())
|
|
||||||
{
|
|
||||||
case HttpRequest::Type::Get:
|
|
||||||
ok = Curl::GetRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
|
|
||||||
break;
|
|
||||||
case HttpRequest::Type::Post:
|
|
||||||
ok = Curl::PostRequest(this, headers, url, data, &response_code, &response_data, &response_header, error_message);
|
|
||||||
break;
|
|
||||||
case HttpRequest::Type::Put:
|
|
||||||
ok = Curl::PutRequest(this, headers, url, data, &response_code, &response_data, &response_header, error_message);
|
|
||||||
break;
|
|
||||||
case HttpRequest::Type::Delete:
|
|
||||||
ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
KGE_ERROR(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
response->SetResponseCode(response_code);
|
|
||||||
response->SetHeader(MultiByteToWide(response_header));
|
|
||||||
response->SetData(convert_from_utf8(response_data));
|
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
response->SetSucceed(false);
|
|
||||||
response->SetError(MultiByteToWide(error_message));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response->SetSucceed(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HttpClient::DispatchResponseCallback()
|
|
||||||
{
|
|
||||||
HttpResponsePtr response;
|
|
||||||
|
|
||||||
response_mutex_.lock();
|
|
||||||
if (!response_queue_.empty())
|
|
||||||
{
|
|
||||||
response = response_queue_.front();
|
|
||||||
response_queue_.pop();
|
|
||||||
}
|
|
||||||
response_mutex_.unlock();
|
|
||||||
|
|
||||||
if (response)
|
|
||||||
{
|
|
||||||
HttpRequestPtr request = response->GetRequest();
|
|
||||||
const auto& callback = request->GetResponseCallback();
|
|
||||||
|
|
||||||
if (callback)
|
|
||||||
{
|
|
||||||
callback(request.get(), response.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpClient::SetupComponent()
|
||||||
|
{
|
||||||
|
::curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
|
||||||
|
std::thread thread(Closure(this, &HttpClient::NetworkThread));
|
||||||
|
thread.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::DestroyComponent()
|
||||||
|
{
|
||||||
|
::curl_global_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::Send(HttpRequestPtr request)
|
||||||
|
{
|
||||||
|
if (!request)
|
||||||
|
return;
|
||||||
|
|
||||||
|
request_mutex_.lock();
|
||||||
|
request_queue_.push(request);
|
||||||
|
request_mutex_.unlock();
|
||||||
|
|
||||||
|
sleep_condition_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::NetworkThread()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
HttpRequestPtr request;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(request_mutex_);
|
||||||
|
while (request_queue_.empty())
|
||||||
|
{
|
||||||
|
sleep_condition_.wait(request_mutex_);
|
||||||
|
}
|
||||||
|
request = request_queue_.front();
|
||||||
|
request_queue_.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponsePtr response = new (std::nothrow) HttpResponse(request);
|
||||||
|
Perform(request, response);
|
||||||
|
|
||||||
|
response_mutex_.lock();
|
||||||
|
response_queue_.push(response);
|
||||||
|
response_mutex_.unlock();
|
||||||
|
|
||||||
|
Application::PreformInMainThread(Closure(this, &HttpClient::DispatchResponseCallback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::Perform(HttpRequestPtr request, HttpResponsePtr response)
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
long response_code = 0;
|
||||||
|
char error_message[256] = { 0 };
|
||||||
|
ByteString response_header;
|
||||||
|
ByteString response_data;
|
||||||
|
|
||||||
|
ByteString url = convert_to_utf8(request->GetUrl());
|
||||||
|
ByteString data = convert_to_utf8(request->GetData());
|
||||||
|
|
||||||
|
Vector<ByteString> headers;
|
||||||
|
headers.reserve(request->GetHeaders().size());
|
||||||
|
for (const auto& pair : request->GetHeaders())
|
||||||
|
{
|
||||||
|
headers.push_back(wide_to_string(pair.first) + ":" + wide_to_string(pair.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (request->GetType())
|
||||||
|
{
|
||||||
|
case HttpRequest::Type::Get:
|
||||||
|
ok = Curl::GetRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
|
||||||
|
break;
|
||||||
|
case HttpRequest::Type::Post:
|
||||||
|
ok = Curl::PostRequest(this, headers, url, data, &response_code, &response_data, &response_header,
|
||||||
|
error_message);
|
||||||
|
break;
|
||||||
|
case HttpRequest::Type::Put:
|
||||||
|
ok =
|
||||||
|
Curl::PutRequest(this, headers, url, data, &response_code, &response_data, &response_header, error_message);
|
||||||
|
break;
|
||||||
|
case HttpRequest::Type::Delete:
|
||||||
|
ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
KGE_ERROR(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response->SetResponseCode(response_code);
|
||||||
|
response->SetHeader(MultiByteToWide(response_header));
|
||||||
|
response->SetData(convert_from_utf8(response_data));
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
response->SetSucceed(false);
|
||||||
|
response->SetError(MultiByteToWide(error_message));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response->SetSucceed(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::DispatchResponseCallback()
|
||||||
|
{
|
||||||
|
HttpResponsePtr response;
|
||||||
|
|
||||||
|
response_mutex_.lock();
|
||||||
|
if (!response_queue_.empty())
|
||||||
|
{
|
||||||
|
response = response_queue_.front();
|
||||||
|
response_queue_.pop();
|
||||||
|
}
|
||||||
|
response_mutex_.unlock();
|
||||||
|
|
||||||
|
if (response)
|
||||||
|
{
|
||||||
|
HttpRequestPtr request = response->GetRequest();
|
||||||
|
const auto& callback = request->GetResponseCallback();
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
{
|
||||||
|
callback(request.get(), response.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace network
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,127 +19,126 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/common.h>
|
#include <condition_variable>
|
||||||
|
#include <kiwano/core/Common.h>
|
||||||
#include <kiwano/core/Component.h>
|
#include <kiwano/core/Component.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace network
|
namespace network
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* \defgroup Network 网络通信
|
* \defgroup Network 网络通信
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Network
|
* \addtogroup Network
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief HTTP客户端
|
* @brief HTTP客户端
|
||||||
*/
|
*/
|
||||||
class KGE_API HttpClient
|
class KGE_API HttpClient
|
||||||
: public Singleton<HttpClient>
|
: public Singleton<HttpClient>
|
||||||
, public ComponentBase
|
, public ComponentBase
|
||||||
{
|
{
|
||||||
friend Singleton<HttpClient>;
|
friend Singleton<HttpClient>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 发送HTTP请求
|
/// @brief 发送HTTP请求
|
||||||
/// @param[in] request HTTP请求
|
/// @param[in] request HTTP请求
|
||||||
/// @details 发送请求后,无论结束或失败都将调用请求的响应回调函数
|
/// @details 发送请求后,无论结束或失败都将调用请求的响应回调函数
|
||||||
void Send(HttpRequestPtr request);
|
void Send(HttpRequestPtr request);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置连接超时时长
|
/// @brief 设置连接超时时长
|
||||||
void SetTimeoutForConnect(Duration timeout);
|
void SetTimeoutForConnect(Duration timeout);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取连接超时时长
|
/// @brief 获取连接超时时长
|
||||||
Duration GetTimeoutForConnect() const;
|
Duration GetTimeoutForConnect() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置读取超时时长
|
/// @brief 设置读取超时时长
|
||||||
void SetTimeoutForRead(Duration timeout);
|
void SetTimeoutForRead(Duration timeout);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取读取超时时长
|
/// @brief 获取读取超时时长
|
||||||
Duration GetTimeoutForRead() const;
|
Duration GetTimeoutForRead() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置SSL证书地址
|
/// @brief 设置SSL证书地址
|
||||||
void SetSSLVerification(String const& root_certificate_path);
|
void SetSSLVerification(String const& root_certificate_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取SSL证书地址
|
/// @brief 获取SSL证书地址
|
||||||
String const& GetSSLVerification() const;
|
String const& GetSSLVerification() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void SetupComponent() override;
|
virtual void SetupComponent() override;
|
||||||
|
|
||||||
virtual void DestroyComponent() override;
|
virtual void DestroyComponent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpClient();
|
HttpClient();
|
||||||
|
|
||||||
void NetworkThread();
|
void NetworkThread();
|
||||||
|
|
||||||
void Perform(HttpRequestPtr request, HttpResponsePtr response);
|
void Perform(HttpRequestPtr request, HttpResponsePtr response);
|
||||||
|
|
||||||
void DispatchResponseCallback();
|
void DispatchResponseCallback();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Duration timeout_for_connect_;
|
Duration timeout_for_connect_;
|
||||||
Duration timeout_for_read_;
|
Duration timeout_for_read_;
|
||||||
|
|
||||||
String ssl_verification_;
|
String ssl_verification_;
|
||||||
|
|
||||||
std::mutex request_mutex_;
|
std::mutex request_mutex_;
|
||||||
Queue<HttpRequestPtr> request_queue_;
|
Queue<HttpRequestPtr> request_queue_;
|
||||||
|
|
||||||
std::mutex response_mutex_;
|
std::mutex response_mutex_;
|
||||||
Queue<HttpResponsePtr> response_queue_;
|
Queue<HttpResponsePtr> response_queue_;
|
||||||
|
|
||||||
std::condition_variable_any sleep_condition_;
|
std::condition_variable_any sleep_condition_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
inline void HttpClient::SetTimeoutForConnect(Duration timeout)
|
||||||
inline void HttpClient::SetTimeoutForConnect(Duration timeout)
|
{
|
||||||
{
|
timeout_for_connect_ = timeout;
|
||||||
timeout_for_connect_ = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Duration HttpClient::GetTimeoutForConnect() const
|
|
||||||
{
|
|
||||||
return timeout_for_connect_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HttpClient::SetTimeoutForRead(Duration timeout)
|
|
||||||
{
|
|
||||||
timeout_for_read_ = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Duration HttpClient::GetTimeoutForRead() const
|
|
||||||
{
|
|
||||||
return timeout_for_read_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HttpClient::SetSSLVerification(String const& root_certificate_path)
|
|
||||||
{
|
|
||||||
ssl_verification_ = root_certificate_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline String const& HttpClient::GetSSLVerification() const
|
|
||||||
{
|
|
||||||
return ssl_verification_;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Duration HttpClient::GetTimeoutForConnect() const
|
||||||
|
{
|
||||||
|
return timeout_for_connect_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpClient::SetTimeoutForRead(Duration timeout)
|
||||||
|
{
|
||||||
|
timeout_for_read_ = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Duration HttpClient::GetTimeoutForRead() const
|
||||||
|
{
|
||||||
|
return timeout_for_read_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpClient::SetSSLVerification(String const& root_certificate_path)
|
||||||
|
{
|
||||||
|
ssl_verification_ = root_certificate_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String const& HttpClient::GetSSLVerification() const
|
||||||
|
{
|
||||||
|
return ssl_verification_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace network
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace network
|
namespace network
|
||||||
{
|
{
|
||||||
void HttpRequest::SetJsonData(Json const& json)
|
void HttpRequest::SetJsonData(Json const& json)
|
||||||
{
|
{
|
||||||
SetHeader(L"Content-Type", L"application/json;charset=UTF-8");
|
SetHeader(L"Content-Type", L"application/json;charset=UTF-8");
|
||||||
data_ = json.dump();
|
data_ = json.dump();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace network
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,138 +19,179 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/common.h>
|
#include <kiwano/core/Common.h>
|
||||||
#include <kiwano/core/ObjectBase.h>
|
#include <kiwano/core/ObjectBase.h>
|
||||||
#include <kiwano/core/SmartPtr.hpp>
|
#include <kiwano/core/SmartPtr.hpp>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace network
|
namespace network
|
||||||
{
|
{
|
||||||
class HttpResponse;
|
class HttpResponse;
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(HttpRequest);
|
KGE_DECLARE_SMART_PTR(HttpRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Network
|
* \addtogroup Network
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief HTTP请求
|
* @brief HTTP请求
|
||||||
*/
|
*/
|
||||||
class KGE_API HttpRequest
|
class KGE_API HttpRequest : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 响应回调函数
|
||||||
/// @brief 响应回调函数
|
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
|
||||||
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 请求类型
|
/// @brief 请求类型
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
Unknown, ///< 未知
|
Unknown, ///< 未知
|
||||||
Get, ///< HTTP GET请求
|
Get, ///< HTTP GET请求
|
||||||
Post, ///< HTTP POST请求
|
Post, ///< HTTP POST请求
|
||||||
Put, ///< HTTP PUT请求
|
Put, ///< HTTP PUT请求
|
||||||
Delete ///< HTTP DELETE请求
|
Delete ///< HTTP DELETE请求
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpRequest();
|
HttpRequest();
|
||||||
|
|
||||||
HttpRequest(Type type);
|
HttpRequest(Type type);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置请求地址
|
/// @brief 设置请求地址
|
||||||
void SetUrl(String const& url);
|
void SetUrl(String const& url);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置请求类型
|
/// @brief 设置请求类型
|
||||||
void SetType(Type type);
|
void SetType(Type type);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置请求携带的数据
|
/// @brief 设置请求携带的数据
|
||||||
void SetData(String const& data);
|
void SetData(String const& data);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置请求携带的JSON数据
|
/// @brief 设置请求携带的JSON数据
|
||||||
void SetJsonData(Json const& json);
|
void SetJsonData(Json const& json);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置HTTP头
|
/// @brief 设置HTTP头
|
||||||
void SetHeaders(Map<String, String> const& headers);
|
void SetHeaders(Map<String, String> const& headers);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置HTTP头
|
/// @brief 设置HTTP头
|
||||||
void SetHeader(String const& field, String const& content);
|
void SetHeader(String const& field, String const& content);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置响应回调函数
|
/// @brief 设置响应回调函数
|
||||||
void SetResponseCallback(ResponseCallback const& callback);
|
void SetResponseCallback(ResponseCallback const& callback);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取请求地址
|
/// @brief 获取请求地址
|
||||||
String const& GetUrl() const;
|
String const& GetUrl() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取请求类型
|
/// @brief 获取请求类型
|
||||||
Type GetType() const;
|
Type GetType() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取请求数据
|
/// @brief 获取请求数据
|
||||||
String const& GetData() const;
|
String const& GetData() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取HTTP头
|
/// @brief 获取HTTP头
|
||||||
Map<String, String>& GetHeaders();
|
Map<String, String>& GetHeaders();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取HTTP头
|
/// @brief 获取HTTP头
|
||||||
String const& GetHeader(String const& header) const;
|
String const& GetHeader(String const& header) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取响应回调函数
|
/// @brief 获取响应回调函数
|
||||||
ResponseCallback const& GetResponseCallback() const;
|
ResponseCallback const& GetResponseCallback() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type_;
|
Type type_;
|
||||||
String url_;
|
String url_;
|
||||||
String data_;
|
String data_;
|
||||||
Map<String, String> headers_;
|
Map<String, String> headers_;
|
||||||
ResponseCallback response_cb_;
|
ResponseCallback response_cb_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline HttpRequest::HttpRequest() : type_(Type::Unknown) {}
|
inline HttpRequest::HttpRequest()
|
||||||
|
: type_(Type::Unknown)
|
||||||
inline HttpRequest::HttpRequest(Type type) : type_(type) {}
|
{
|
||||||
|
|
||||||
inline void HttpRequest::SetUrl(String const& url) { url_ = url; }
|
|
||||||
|
|
||||||
inline String const& HttpRequest::GetUrl() const { return url_; }
|
|
||||||
|
|
||||||
inline void HttpRequest::SetType(Type type) { type_ = type; }
|
|
||||||
|
|
||||||
inline HttpRequest::Type HttpRequest::GetType() const { return type_; }
|
|
||||||
|
|
||||||
inline void HttpRequest::SetData(String const& data) { data_ = data; }
|
|
||||||
|
|
||||||
inline String const& HttpRequest::GetData() const { return data_; }
|
|
||||||
|
|
||||||
inline void HttpRequest::SetHeaders(Map<String, String> const& headers) { headers_ = headers; }
|
|
||||||
|
|
||||||
inline void HttpRequest::SetHeader(String const& field, String const& content) { headers_[field] = content; }
|
|
||||||
|
|
||||||
inline Map<String, String>& HttpRequest::GetHeaders() { return headers_; }
|
|
||||||
|
|
||||||
inline String const& HttpRequest::GetHeader(String const& header) const { return headers_.at(header); }
|
|
||||||
|
|
||||||
inline void HttpRequest::SetResponseCallback(ResponseCallback const& callback) { response_cb_ = callback; }
|
|
||||||
|
|
||||||
inline HttpRequest::ResponseCallback const& HttpRequest::GetResponseCallback() const { return response_cb_; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline HttpRequest::HttpRequest(Type type)
|
||||||
|
: type_(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpRequest::SetUrl(String const& url)
|
||||||
|
{
|
||||||
|
url_ = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String const& HttpRequest::GetUrl() const
|
||||||
|
{
|
||||||
|
return url_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpRequest::SetType(Type type)
|
||||||
|
{
|
||||||
|
type_ = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline HttpRequest::Type HttpRequest::GetType() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpRequest::SetData(String const& data)
|
||||||
|
{
|
||||||
|
data_ = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String const& HttpRequest::GetData() const
|
||||||
|
{
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpRequest::SetHeaders(Map<String, String> const& headers)
|
||||||
|
{
|
||||||
|
headers_ = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpRequest::SetHeader(String const& field, String const& content)
|
||||||
|
{
|
||||||
|
headers_[field] = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Map<String, String>& HttpRequest::GetHeaders()
|
||||||
|
{
|
||||||
|
return headers_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String const& HttpRequest::GetHeader(String const& header) const
|
||||||
|
{
|
||||||
|
return headers_.at(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpRequest::SetResponseCallback(ResponseCallback const& callback)
|
||||||
|
{
|
||||||
|
response_cb_ = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline HttpRequest::ResponseCallback const& HttpRequest::GetResponseCallback() const
|
||||||
|
{
|
||||||
|
return response_cb_;
|
||||||
|
}
|
||||||
|
} // namespace network
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,103 +23,140 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace network
|
namespace network
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(HttpResponse);
|
KGE_DECLARE_SMART_PTR(HttpResponse);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Network
|
* \addtogroup Network
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief HTTP响应
|
* @brief HTTP响应
|
||||||
*/
|
*/
|
||||||
class KGE_API HttpResponse
|
class KGE_API HttpResponse : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
public:
|
||||||
public:
|
HttpResponse(HttpRequestPtr request);
|
||||||
HttpResponse(HttpRequestPtr request);
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取对应的HTTP请求
|
/// @brief 获取对应的HTTP请求
|
||||||
HttpRequestPtr GetRequest() const;
|
HttpRequestPtr GetRequest() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取响应状态
|
/// @brief 获取响应状态
|
||||||
bool IsSucceed() const;
|
bool IsSucceed() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取HTTP状态码
|
/// @brief 获取HTTP状态码
|
||||||
long GetResponseCode() const;
|
long GetResponseCode() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取响应头
|
/// @brief 获取响应头
|
||||||
String GetHeader() const;
|
String GetHeader() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取响应数据
|
/// @brief 获取响应数据
|
||||||
String const& GetData() const;
|
String const& GetData() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取错误信息
|
/// @brief 获取错误信息
|
||||||
String const& GetError() const;
|
String const& GetError() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置响应状态
|
/// @brief 设置响应状态
|
||||||
void SetSucceed(bool succeed);
|
void SetSucceed(bool succeed);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置HTTP状态码
|
/// @brief 设置HTTP状态码
|
||||||
void SetResponseCode(long response_code);
|
void SetResponseCode(long response_code);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置响应头
|
/// @brief 设置响应头
|
||||||
void SetHeader(String const& response_header);
|
void SetHeader(String const& response_header);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置响应数据
|
/// @brief 设置响应数据
|
||||||
void SetData(String const& response_data);
|
void SetData(String const& response_data);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置错误信息
|
/// @brief 设置错误信息
|
||||||
void SetError(String const& error_buffer);
|
void SetError(String const& error_buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool succeed_;
|
bool succeed_;
|
||||||
long response_code_;
|
long response_code_;
|
||||||
HttpRequestPtr request_;
|
HttpRequestPtr request_;
|
||||||
|
|
||||||
String response_header_;
|
String response_header_;
|
||||||
String response_data_;
|
String response_data_;
|
||||||
String error_buffer_;
|
String error_buffer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline HttpResponse::HttpResponse(HttpRequestPtr request) : request_(request), succeed_(false), response_code_(0) {}
|
inline HttpResponse::HttpResponse(HttpRequestPtr request)
|
||||||
|
: request_(request)
|
||||||
inline HttpRequestPtr HttpResponse::GetRequest() const { return request_; }
|
, succeed_(false)
|
||||||
|
, response_code_(0)
|
||||||
inline void HttpResponse::SetSucceed(bool succeed) { succeed_ = succeed; }
|
{
|
||||||
|
|
||||||
inline bool HttpResponse::IsSucceed() const { return succeed_; }
|
|
||||||
|
|
||||||
inline void HttpResponse::SetResponseCode(long response_code) { response_code_ = response_code; }
|
|
||||||
|
|
||||||
inline long HttpResponse::GetResponseCode() const { return response_code_; }
|
|
||||||
|
|
||||||
inline void HttpResponse::SetHeader(String const& response_header) { response_header_ = response_header; }
|
|
||||||
|
|
||||||
inline String HttpResponse::GetHeader() const { return response_header_; }
|
|
||||||
|
|
||||||
inline void HttpResponse::SetData(String const& response_data) { response_data_ = response_data; }
|
|
||||||
|
|
||||||
inline String const& HttpResponse::GetData() const { return response_data_; }
|
|
||||||
|
|
||||||
inline void HttpResponse::SetError(String const& error_buffer) { error_buffer_ = error_buffer; }
|
|
||||||
|
|
||||||
inline String const& HttpResponse::GetError() const { return error_buffer_; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline HttpRequestPtr HttpResponse::GetRequest() const
|
||||||
|
{
|
||||||
|
return request_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpResponse::SetSucceed(bool succeed)
|
||||||
|
{
|
||||||
|
succeed_ = succeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool HttpResponse::IsSucceed() const
|
||||||
|
{
|
||||||
|
return succeed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpResponse::SetResponseCode(long response_code)
|
||||||
|
{
|
||||||
|
response_code_ = response_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline long HttpResponse::GetResponseCode() const
|
||||||
|
{
|
||||||
|
return response_code_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpResponse::SetHeader(String const& response_header)
|
||||||
|
{
|
||||||
|
response_header_ = response_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String HttpResponse::GetHeader() const
|
||||||
|
{
|
||||||
|
return response_header_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpResponse::SetData(String const& response_data)
|
||||||
|
{
|
||||||
|
response_data_ = response_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String const& HttpResponse::GetData() const
|
||||||
|
{
|
||||||
|
return response_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HttpResponse::SetError(String const& error_buffer)
|
||||||
|
{
|
||||||
|
error_buffer_ = error_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String const& HttpResponse::GetError() const
|
||||||
|
{
|
||||||
|
return error_buffer_;
|
||||||
|
}
|
||||||
|
} // namespace network
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <kiwano-network/HttpClient.h>
|
||||||
#include <kiwano-network/HttpRequest.h>
|
#include <kiwano-network/HttpRequest.h>
|
||||||
#include <kiwano-network/HttpResponse.hpp>
|
#include <kiwano-network/HttpResponse.hpp>
|
||||||
#include <kiwano-network/HttpClient.h>
|
|
||||||
|
|
|
||||||
|
|
@ -23,291 +23,280 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
|
|
||||||
Body::Body()
|
|
||||||
: body_(nullptr)
|
|
||||||
, actor_(nullptr)
|
|
||||||
, world_(nullptr)
|
|
||||||
, category_bits_(0x0001)
|
|
||||||
, mask_bits_(0xFFFF)
|
|
||||||
, group_index_(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Body::Body(b2Body* body, Actor* actor)
|
|
||||||
: Body()
|
|
||||||
{
|
|
||||||
SetB2Body(body);
|
|
||||||
SetActor(actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Body::Body(World* world, Actor* actor)
|
|
||||||
: Body()
|
|
||||||
{
|
|
||||||
Init(world, actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Body::~Body()
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::Init(World* world, Actor* actor)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
Destroy();
|
|
||||||
|
|
||||||
world_ = world;
|
|
||||||
b2BodyDef def;
|
|
||||||
b2Body* b2body = world->GetB2World()->CreateBody(&def);
|
|
||||||
|
|
||||||
SetB2Body(b2body);
|
|
||||||
SetActor(actor);
|
|
||||||
UpdateFromActor();
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Body::AddFixture(Shape* shape, const Fixture::Param& param)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
return Fixture(this, shape, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Body::AddCircleShape(float radius, float density)
|
|
||||||
{
|
|
||||||
return AddFixture(&CircleShape(radius), Fixture::Param(density));
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Body::AddBoxShape(Vec2 const& size, float density)
|
|
||||||
{
|
|
||||||
return AddFixture(&BoxShape(size), Fixture::Param(density));
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Body::AddPolygonShape(Vector<Point> const& vertexs, float density)
|
|
||||||
{
|
|
||||||
return AddFixture(&PolygonShape(vertexs), Fixture::Param(density));
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Body::AddEdgeShape(Point const& p1, Point const& p2, float density)
|
|
||||||
{
|
|
||||||
return AddFixture(&EdgeShape(p1, p2), Fixture::Param(density));
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Body::AddChainShape(Vector<Point> const& vertexs, bool loop, float density)
|
|
||||||
{
|
|
||||||
return AddFixture(&ChainShape(vertexs, loop), Fixture::Param(density));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::RemoveFixture(Fixture const& fixture)
|
|
||||||
{
|
|
||||||
if (fixture.GetB2Fixture())
|
|
||||||
{
|
|
||||||
body_->DestroyFixture(fixture.GetB2Fixture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::SetCategoryBits(uint16_t category_bits)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_);
|
|
||||||
|
|
||||||
if (category_bits != category_bits_)
|
|
||||||
{
|
|
||||||
category_bits_ = category_bits;
|
|
||||||
|
|
||||||
b2Fixture* fixture = body_->GetFixtureList();
|
|
||||||
while (fixture)
|
|
||||||
{
|
|
||||||
UpdateFixtureFilter(fixture);
|
|
||||||
fixture = fixture->GetNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::SetMaskBits(uint16_t mask_bits)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_);
|
|
||||||
|
|
||||||
if (mask_bits != mask_bits_)
|
|
||||||
{
|
|
||||||
mask_bits_ = mask_bits;
|
|
||||||
|
|
||||||
b2Fixture* fixture = body_->GetFixtureList();
|
|
||||||
while (fixture)
|
|
||||||
{
|
|
||||||
UpdateFixtureFilter(fixture);
|
|
||||||
fixture = fixture->GetNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::SetGroupIndex(int16_t index)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_);
|
|
||||||
|
|
||||||
if (index != group_index_)
|
|
||||||
{
|
|
||||||
group_index_ = index;
|
|
||||||
|
|
||||||
b2Fixture* fixture = body_->GetFixtureList();
|
|
||||||
while (fixture)
|
|
||||||
{
|
|
||||||
UpdateFixtureFilter(fixture);
|
|
||||||
fixture = fixture->GetNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::GetMassData(float* mass, Point* center, float* inertia) const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
|
|
||||||
b2MassData data;
|
|
||||||
body_->GetMassData(&data);
|
|
||||||
|
|
||||||
if (mass) *mass = data.mass;
|
|
||||||
if (center) *center = world_->World2Stage(data.center);
|
|
||||||
if (inertia) *inertia = data.I;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::SetMassData(float mass, Point const& center, float inertia)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
|
|
||||||
b2MassData data;
|
|
||||||
data.mass = mass;
|
|
||||||
data.center = world_->Stage2World(center);
|
|
||||||
data.I = inertia;
|
|
||||||
body_->SetMassData(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::ResetMassData()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_);
|
|
||||||
body_->ResetMassData();
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Body::GetBodyPosition() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
return world_->World2Stage(body_->GetPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::SetBodyTransform(Point const& pos, float angle)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
body_->SetTransform(world_->Stage2World(pos), math::Degree2Radian(angle));
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Body::GetLocalPoint(Point const& world) const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
return world_->World2Stage(body_->GetLocalPoint(world_->Stage2World(world)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Body::GetWorldPoint(Point const& local) const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
return world_->World2Stage(body_->GetWorldPoint(world_->Stage2World(local)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Body::GetLocalCenter() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
return world_->World2Stage(body_->GetLocalCenter());
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Body::GetWorldCenter() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
return world_->World2Stage(body_->GetWorldCenter());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::ApplyForce(Vec2 const& force, Point const& point, bool wake)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
body_->ApplyForce(b2Vec2(force.x, force.y), world_->Stage2World(point), wake);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::ApplyForceToCenter(Vec2 const& force, bool wake)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
body_->ApplyForceToCenter(b2Vec2(force.x, force.y), wake);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::ApplyTorque(float torque, bool wake)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body_ && world_);
|
|
||||||
body_->ApplyTorque(torque, wake);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::SetB2Body(b2Body* body)
|
|
||||||
{
|
|
||||||
body_ = body;
|
|
||||||
if (body_)
|
|
||||||
{
|
|
||||||
body_->SetUserData(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::Destroy()
|
|
||||||
{
|
|
||||||
if (world_ && body_)
|
|
||||||
{
|
|
||||||
world_->RemoveBody(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
body_ = nullptr;
|
|
||||||
world_ = nullptr;
|
|
||||||
actor_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::UpdateActor()
|
|
||||||
{
|
|
||||||
if (actor_ && body_)
|
|
||||||
{
|
|
||||||
if (world_)
|
|
||||||
{
|
|
||||||
actor_->SetPosition(world_->World2Stage(body_->GetPosition()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actor_->SetPosition(World2Stage(body_->GetPosition()));
|
|
||||||
}
|
|
||||||
actor_->SetRotation(math::Radian2Degree(body_->GetAngle()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::UpdateFromActor()
|
|
||||||
{
|
|
||||||
if (actor_ && body_)
|
|
||||||
{
|
|
||||||
if (world_)
|
|
||||||
{
|
|
||||||
body_->SetTransform(
|
|
||||||
world_->Stage2World(actor_->GetPosition()),
|
|
||||||
math::Degree2Radian(actor_->GetRotation())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
body_->SetTransform(
|
|
||||||
Stage2World(actor_->GetPosition()),
|
|
||||||
math::Degree2Radian(actor_->GetRotation())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Body::UpdateFixtureFilter(b2Fixture* fixture)
|
|
||||||
{
|
|
||||||
b2Filter filter;
|
|
||||||
filter.categoryBits = category_bits_;
|
|
||||||
filter.maskBits = mask_bits_;
|
|
||||||
filter.groupIndex = group_index_;
|
|
||||||
fixture->SetFilterData(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Body::Body()
|
||||||
|
: body_(nullptr)
|
||||||
|
, actor_(nullptr)
|
||||||
|
, world_(nullptr)
|
||||||
|
, category_bits_(0x0001)
|
||||||
|
, mask_bits_(0xFFFF)
|
||||||
|
, group_index_(0)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Body::~Body()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Body::InitBody(World* world, Actor* actor)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
world_ = world;
|
||||||
|
b2BodyDef def;
|
||||||
|
b2Body* b2body = world->GetB2World()->CreateBody(&def);
|
||||||
|
|
||||||
|
if (b2body)
|
||||||
|
{
|
||||||
|
SetB2Body(b2body);
|
||||||
|
SetActor(actor);
|
||||||
|
UpdateFromActor();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Body::AddFixture(Shape* shape, const Fixture::Param& param)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
return Fixture(this, shape, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Body::AddCircleShape(float radius, float density)
|
||||||
|
{
|
||||||
|
return AddFixture(&CircleShape(radius), Fixture::Param(density));
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Body::AddBoxShape(Vec2 const& size, float density)
|
||||||
|
{
|
||||||
|
return AddFixture(&BoxShape(size), Fixture::Param(density));
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Body::AddPolygonShape(Vector<Point> const& vertexs, float density)
|
||||||
|
{
|
||||||
|
return AddFixture(&PolygonShape(vertexs), Fixture::Param(density));
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Body::AddEdgeShape(Point const& p1, Point const& p2, float density)
|
||||||
|
{
|
||||||
|
return AddFixture(&EdgeShape(p1, p2), Fixture::Param(density));
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Body::AddChainShape(Vector<Point> const& vertexs, bool loop, float density)
|
||||||
|
{
|
||||||
|
return AddFixture(&ChainShape(vertexs, loop), Fixture::Param(density));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::RemoveFixture(Fixture const& fixture)
|
||||||
|
{
|
||||||
|
if (fixture.GetB2Fixture())
|
||||||
|
{
|
||||||
|
body_->DestroyFixture(fixture.GetB2Fixture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::SetCategoryBits(uint16_t category_bits)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_);
|
||||||
|
|
||||||
|
if (category_bits != category_bits_)
|
||||||
|
{
|
||||||
|
category_bits_ = category_bits;
|
||||||
|
|
||||||
|
b2Fixture* fixture = body_->GetFixtureList();
|
||||||
|
while (fixture)
|
||||||
|
{
|
||||||
|
UpdateFixtureFilter(fixture);
|
||||||
|
fixture = fixture->GetNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::SetMaskBits(uint16_t mask_bits)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_);
|
||||||
|
|
||||||
|
if (mask_bits != mask_bits_)
|
||||||
|
{
|
||||||
|
mask_bits_ = mask_bits;
|
||||||
|
|
||||||
|
b2Fixture* fixture = body_->GetFixtureList();
|
||||||
|
while (fixture)
|
||||||
|
{
|
||||||
|
UpdateFixtureFilter(fixture);
|
||||||
|
fixture = fixture->GetNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::SetGroupIndex(int16_t index)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_);
|
||||||
|
|
||||||
|
if (index != group_index_)
|
||||||
|
{
|
||||||
|
group_index_ = index;
|
||||||
|
|
||||||
|
b2Fixture* fixture = body_->GetFixtureList();
|
||||||
|
while (fixture)
|
||||||
|
{
|
||||||
|
UpdateFixtureFilter(fixture);
|
||||||
|
fixture = fixture->GetNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::GetMassData(float* mass, Point* center, float* inertia) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
|
||||||
|
b2MassData data;
|
||||||
|
body_->GetMassData(&data);
|
||||||
|
|
||||||
|
if (mass)
|
||||||
|
*mass = data.mass;
|
||||||
|
if (center)
|
||||||
|
*center = world_->World2Stage(data.center);
|
||||||
|
if (inertia)
|
||||||
|
*inertia = data.I;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::SetMassData(float mass, Point const& center, float inertia)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
|
||||||
|
b2MassData data;
|
||||||
|
data.mass = mass;
|
||||||
|
data.center = world_->Stage2World(center);
|
||||||
|
data.I = inertia;
|
||||||
|
body_->SetMassData(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::ResetMassData()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_);
|
||||||
|
body_->ResetMassData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Body::GetBodyPosition() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
return world_->World2Stage(body_->GetPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::SetBodyTransform(Point const& pos, float angle)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
body_->SetTransform(world_->Stage2World(pos), math::Degree2Radian(angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Body::GetLocalPoint(Point const& world) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
return world_->World2Stage(body_->GetLocalPoint(world_->Stage2World(world)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Body::GetWorldPoint(Point const& local) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
return world_->World2Stage(body_->GetWorldPoint(world_->Stage2World(local)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Body::GetLocalCenter() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
return world_->World2Stage(body_->GetLocalCenter());
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Body::GetWorldCenter() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
return world_->World2Stage(body_->GetWorldCenter());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::ApplyForce(Vec2 const& force, Point const& point, bool wake)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
body_->ApplyForce(b2Vec2(force.x, force.y), world_->Stage2World(point), wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::ApplyForceToCenter(Vec2 const& force, bool wake)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
body_->ApplyForceToCenter(b2Vec2(force.x, force.y), wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::ApplyTorque(float torque, bool wake)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body_ && world_);
|
||||||
|
body_->ApplyTorque(torque, wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::SetB2Body(b2Body* body)
|
||||||
|
{
|
||||||
|
body_ = body;
|
||||||
|
if (body_)
|
||||||
|
{
|
||||||
|
body_->SetUserData(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::Destroy()
|
||||||
|
{
|
||||||
|
if (world_)
|
||||||
|
{
|
||||||
|
world_->RemoveBody(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
body_ = nullptr;
|
||||||
|
world_ = nullptr;
|
||||||
|
actor_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::UpdateActor()
|
||||||
|
{
|
||||||
|
if (actor_ && body_)
|
||||||
|
{
|
||||||
|
if (world_)
|
||||||
|
{
|
||||||
|
actor_->SetPosition(world_->World2Stage(body_->GetPosition()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actor_->SetPosition(World2Stage(body_->GetPosition()));
|
||||||
|
}
|
||||||
|
actor_->SetRotation(math::Radian2Degree(body_->GetAngle()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::UpdateFromActor()
|
||||||
|
{
|
||||||
|
if (actor_ && body_)
|
||||||
|
{
|
||||||
|
if (world_)
|
||||||
|
{
|
||||||
|
body_->SetTransform(world_->Stage2World(actor_->GetPosition()), math::Degree2Radian(actor_->GetRotation()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
body_->SetTransform(Stage2World(actor_->GetPosition()), math::Degree2Radian(actor_->GetRotation()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::UpdateFixtureFilter(b2Fixture* fixture)
|
||||||
|
{
|
||||||
|
b2Filter filter;
|
||||||
|
filter.categoryBits = category_bits_;
|
||||||
|
filter.maskBits = mask_bits_;
|
||||||
|
filter.groupIndex = group_index_;
|
||||||
|
fixture->SetFilterData(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,362 +19,471 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano-physics/helper.h>
|
|
||||||
#include <kiwano-physics/Shape.h>
|
|
||||||
#include <kiwano-physics/Fixture.h>
|
|
||||||
#include <kiwano-physics/ContactEdge.h>
|
#include <kiwano-physics/ContactEdge.h>
|
||||||
|
#include <kiwano-physics/Fixture.h>
|
||||||
|
#include <kiwano-physics/Shape.h>
|
||||||
|
#include <kiwano-physics/helper.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
class World;
|
class World;
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(Body);
|
KGE_DECLARE_SMART_PTR(Body);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Physics
|
* \addtogroup Physics
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 物体
|
/// @brief 物体
|
||||||
class KGE_API Body
|
class KGE_API Body : public virtual ObjectBase
|
||||||
: public virtual RefCounter
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 物体类型
|
||||||
/// @brief 物体类型
|
enum class Type
|
||||||
enum class Type
|
{
|
||||||
{
|
Static = 0, ///< 静态物体
|
||||||
Static = 0, ///< 静态物体
|
Kinematic, ///< 动力学物体
|
||||||
Kinematic, ///< 动力学物体
|
Dynamic, ///< 动态物体
|
||||||
Dynamic, ///< 动态物体
|
};
|
||||||
};
|
|
||||||
|
Body();
|
||||||
Body();
|
|
||||||
Body(b2Body* body, Actor* actor);
|
virtual ~Body();
|
||||||
Body(World* world, Actor* actor);
|
|
||||||
Body(World* world, ActorPtr actor);
|
/// \~chinese
|
||||||
virtual ~Body();
|
/// @brief 初始化
|
||||||
|
/// @param[in] world 物理世界
|
||||||
/// \~chinese
|
/// @param[in] actor 绑定的角色
|
||||||
/// @brief 初始化
|
bool InitBody(World* world, ActorPtr actor);
|
||||||
/// @param[in] world 物理世界
|
|
||||||
/// @param[in] actor 绑定的角色
|
/// \~chinese
|
||||||
void Init(World* world, Actor* actor);
|
/// @brief 初始化
|
||||||
|
/// @param[in] world 物理世界
|
||||||
/// \~chinese
|
/// @param[in] actor 绑定的角色
|
||||||
/// @brief 添加夹具
|
bool InitBody(World* world, Actor* actor);
|
||||||
/// @param shape 物体形状
|
|
||||||
/// @param density 物体密度
|
/// \~chinese
|
||||||
Fixture AddFixture(Shape* shape, const Fixture::Param& param);
|
/// @brief 添加夹具
|
||||||
|
/// @param shape 物体形状
|
||||||
/// \~chinese
|
/// @param density 物体密度
|
||||||
/// @brief 添加圆形夹具
|
Fixture AddFixture(Shape* shape, const Fixture::Param& param);
|
||||||
/// @param radius 圆形半径
|
|
||||||
/// @param density 物体密度
|
/// \~chinese
|
||||||
Fixture AddCircleShape(float radius, float density = 0.f);
|
/// @brief 添加圆形夹具
|
||||||
|
/// @param radius 圆形半径
|
||||||
/// \~chinese
|
/// @param density 物体密度
|
||||||
/// @brief 添加盒形夹具
|
Fixture AddCircleShape(float radius, float density = 0.f);
|
||||||
/// @param size 盒大小
|
|
||||||
/// @param density 物体密度
|
/// \~chinese
|
||||||
Fixture AddBoxShape(Vec2 const& size, float density = 0.f);
|
/// @brief 添加盒形夹具
|
||||||
|
/// @param size 盒大小
|
||||||
/// \~chinese
|
/// @param density 物体密度
|
||||||
/// @brief 添加多边形夹具
|
Fixture AddBoxShape(Vec2 const& size, float density = 0.f);
|
||||||
/// @param vertexs 多边形端点
|
|
||||||
/// @param density 物体密度
|
/// \~chinese
|
||||||
Fixture AddPolygonShape(Vector<Point> const& vertexs, float density = 0.f);
|
/// @brief 添加多边形夹具
|
||||||
|
/// @param vertexs 多边形端点
|
||||||
/// \~chinese
|
/// @param density 物体密度
|
||||||
/// @brief 添加线段形夹具
|
Fixture AddPolygonShape(Vector<Point> const& vertexs, float density = 0.f);
|
||||||
/// @param p1 线段起点
|
|
||||||
/// @param p2 线段终点
|
/// \~chinese
|
||||||
/// @param density 物体密度
|
/// @brief 添加线段形夹具
|
||||||
Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f);
|
/// @param p1 线段起点
|
||||||
|
/// @param p2 线段终点
|
||||||
/// \~chinese
|
/// @param density 物体密度
|
||||||
/// @brief 添加链条形夹具
|
Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f);
|
||||||
/// @param vertexs 链条端点
|
|
||||||
/// @param loop 是否闭合
|
/// \~chinese
|
||||||
/// @param density 物体密度
|
/// @brief 添加链条形夹具
|
||||||
Fixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
|
/// @param vertexs 链条端点
|
||||||
|
/// @param loop 是否闭合
|
||||||
/// \~chinese
|
/// @param density 物体密度
|
||||||
/// @brief 获取夹具列表
|
Fixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
|
||||||
FixtureList GetFixtureList() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取夹具列表
|
||||||
/// @brief 移除夹具
|
FixtureList GetFixtureList() const;
|
||||||
void RemoveFixture(Fixture const& fixture);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 移除夹具
|
||||||
/// @brief 获取接触边列表
|
void RemoveFixture(Fixture const& fixture);
|
||||||
ContactEdgeList GetContactList() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取接触边列表
|
||||||
/// @brief 获取类别码
|
ContactEdgeList GetContactList() const;
|
||||||
uint16_t GetCategoryBits() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取类别码
|
||||||
/// @brief 设置类别码
|
uint16_t GetCategoryBits() const;
|
||||||
void SetCategoryBits(uint16_t category_bits);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置类别码
|
||||||
/// @brief 获取碰撞掩码
|
void SetCategoryBits(uint16_t category_bits);
|
||||||
uint16_t GetMaskBits() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取碰撞掩码
|
||||||
/// @brief 设置碰撞掩码
|
uint16_t GetMaskBits() const;
|
||||||
void SetMaskBits(uint16_t mask_bits);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置碰撞掩码
|
||||||
/// @brief 获取组索引
|
void SetMaskBits(uint16_t mask_bits);
|
||||||
int16_t GetGroupIndex() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取组索引
|
||||||
/// @brief 设置组索引
|
int16_t GetGroupIndex() const;
|
||||||
void SetGroupIndex(int16_t index);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置组索引
|
||||||
/// @brief 获取旋转角度
|
void SetGroupIndex(int16_t index);
|
||||||
float GetBodyRotation() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取旋转角度
|
||||||
/// @brief 设置旋转角度
|
float GetBodyRotation() const;
|
||||||
void SetBodyRotation(float angle);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置旋转角度
|
||||||
/// @brief 获取物体位置
|
void SetBodyRotation(float angle);
|
||||||
Point GetBodyPosition() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体位置
|
||||||
/// @brief 设置物体位置
|
Point GetBodyPosition() const;
|
||||||
void SetBodyPosition(Point const& pos);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置物体位置
|
||||||
/// @brief 位置和旋转变换
|
void SetBodyPosition(Point const& pos);
|
||||||
void SetBodyTransform(Point const& pos, float angle);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 位置和旋转变换
|
||||||
/// @brief 获取质量 [kg]
|
void SetBodyTransform(Point const& pos, float angle);
|
||||||
float GetMass() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取质量 [kg]
|
||||||
/// @brief 获取惯性
|
float GetMass() const;
|
||||||
float GetInertia() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取惯性
|
||||||
/// @brief 获取质量数据
|
float GetInertia() const;
|
||||||
/// @param[out] mass 物体质量 [kg]
|
|
||||||
/// @param[out] center 质心位置
|
/// \~chinese
|
||||||
/// @param[out] inertia 惯性
|
/// @brief 获取质量数据
|
||||||
void GetMassData(float* mass, Point* center, float* inertia) const;
|
/// @param[out] mass 物体质量 [kg]
|
||||||
|
/// @param[out] center 质心位置
|
||||||
/// \~chinese
|
/// @param[out] inertia 惯性
|
||||||
/// @brief 设置质量数据
|
void GetMassData(float* mass, Point* center, float* inertia) const;
|
||||||
/// @param mass 物体质量 [kg]
|
|
||||||
/// @param center 质心位置
|
/// \~chinese
|
||||||
/// @param inertia 惯性
|
/// @brief 设置质量数据
|
||||||
void SetMassData(float mass, Point const& center, float inertia);
|
/// @param mass 物体质量 [kg]
|
||||||
|
/// @param center 质心位置
|
||||||
/// \~chinese
|
/// @param inertia 惯性
|
||||||
/// @brief 重置质量数据
|
void SetMassData(float mass, Point const& center, float inertia);
|
||||||
void ResetMassData();
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 重置质量数据
|
||||||
/// @brief 获取世界坐标系上的点在物体上的位置
|
void ResetMassData();
|
||||||
Point GetLocalPoint(Point const& world) const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取世界坐标系上的点在物体上的位置
|
||||||
/// @brief 获取物体上的点在世界坐标系的位置
|
Point GetLocalPoint(Point const& world) const;
|
||||||
Point GetWorldPoint(Point const& local) const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体上的点在世界坐标系的位置
|
||||||
/// @brief 获取物体质心相对于物体的位置
|
Point GetWorldPoint(Point const& local) const;
|
||||||
Point GetLocalCenter() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体质心相对于物体的位置
|
||||||
/// @brief 获取物体质心位置
|
Point GetLocalCenter() const;
|
||||||
Point GetWorldCenter() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体质心位置
|
||||||
/// @brief 获取物体类型
|
Point GetWorldCenter() const;
|
||||||
Type GetType() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体类型
|
||||||
/// @brief 设置物体类型
|
Type GetType() const;
|
||||||
void SetType(Type type);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置物体类型
|
||||||
/// @brief 获取物体受重力的比例
|
void SetType(Type type);
|
||||||
float GetGravityScale() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体受重力的比例
|
||||||
/// @brief 设置物体受重力的比例
|
float GetGravityScale() const;
|
||||||
void SetGravityScale(float scale);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置物体受重力的比例
|
||||||
/// @brief 施力
|
void SetGravityScale(float scale);
|
||||||
/// @param force 力的大小和方向
|
|
||||||
/// @param point 施力点
|
/// \~chinese
|
||||||
/// @param wake 是否唤醒物体
|
/// @brief 施力
|
||||||
void ApplyForce(Vec2 const& force, Point const& point, bool wake = true);
|
/// @param force 力的大小和方向
|
||||||
|
/// @param point 施力点
|
||||||
/// \~chinese
|
/// @param wake 是否唤醒物体
|
||||||
/// @brief 给物体中心施力
|
void ApplyForce(Vec2 const& force, Point const& point, bool wake = true);
|
||||||
/// @param force 力的大小和方向
|
|
||||||
/// @param wake 是否唤醒物体
|
/// \~chinese
|
||||||
void ApplyForceToCenter(Vec2 const& force, bool wake = true);
|
/// @brief 给物体中心施力
|
||||||
|
/// @param force 力的大小和方向
|
||||||
/// \~chinese
|
/// @param wake 是否唤醒物体
|
||||||
/// @brief 施加扭矩
|
void ApplyForceToCenter(Vec2 const& force, bool wake = true);
|
||||||
/// @param torque 扭矩
|
|
||||||
/// @param wake 是否唤醒物体
|
/// \~chinese
|
||||||
void ApplyTorque(float torque, bool wake = false);
|
/// @brief 施加扭矩
|
||||||
|
/// @param torque 扭矩
|
||||||
/// \~chinese
|
/// @param wake 是否唤醒物体
|
||||||
/// @brief 旋转角度是否固定
|
void ApplyTorque(float torque, bool wake = false);
|
||||||
bool IsIgnoreRotation() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 旋转角度是否固定
|
||||||
/// @brief 设置是否固定旋转角度
|
bool IsIgnoreRotation() const;
|
||||||
void SetIgnoreRotation(bool flag);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置是否固定旋转角度
|
||||||
/// @brief 是否是子弹物体
|
void SetIgnoreRotation(bool flag);
|
||||||
bool IsBullet() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 是否是子弹物体
|
||||||
/// @brief 设置物体是否是子弹物体
|
bool IsBullet() const;
|
||||||
void SetBullet(bool flag);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置物体是否是子弹物体
|
||||||
/// @brief 是否处于唤醒状态
|
void SetBullet(bool flag);
|
||||||
bool IsAwake() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 是否处于唤醒状态
|
||||||
/// @brief 设置唤醒状态
|
bool IsAwake() const;
|
||||||
void SetAwake(bool flag);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置唤醒状态
|
||||||
/// @brief 是否启用休眠
|
void SetAwake(bool flag);
|
||||||
bool IsSleepingAllowed() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 是否启用休眠
|
||||||
/// @brief 设置是否允许休眠
|
bool IsSleepingAllowed() const;
|
||||||
void SetSleepingAllowed(bool flag);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置是否允许休眠
|
||||||
/// @brief 是否启用
|
void SetSleepingAllowed(bool flag);
|
||||||
bool IsActive() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 是否启用
|
||||||
/// @brief 设置启用状态
|
bool IsActive() const;
|
||||||
void SetActive(bool flag);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置启用状态
|
||||||
/// @brief 获取物体所在物理世界
|
void SetActive(bool flag);
|
||||||
World* GetWorld() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体所在物理世界
|
||||||
/// @brief 获取物体绑定的角色
|
World* GetWorld() const;
|
||||||
Actor* GetActor() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取物体绑定的角色
|
||||||
/// @brief 设置物体绑定的角色
|
Actor* GetActor() const;
|
||||||
void SetActor(Actor* actor);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置物体绑定的角色
|
||||||
/// @brief 将物体信息更新到角色
|
void SetActor(Actor* actor);
|
||||||
void UpdateActor();
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 将物体信息更新到角色
|
||||||
/// @brief 将角色信息更新到物体
|
void UpdateActor();
|
||||||
void UpdateFromActor();
|
|
||||||
|
/// \~chinese
|
||||||
b2Body* GetB2Body() const;
|
/// @brief 将角色信息更新到物体
|
||||||
void SetB2Body(b2Body* body);
|
void UpdateFromActor();
|
||||||
|
|
||||||
private:
|
b2Body* GetB2Body() const;
|
||||||
/// \~chinese
|
void SetB2Body(b2Body* body);
|
||||||
/// @brief 销毁物体
|
|
||||||
void UpdateFixtureFilter(b2Fixture* fixture);
|
private:
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 销毁物体
|
||||||
/// @brief 销毁物体
|
void UpdateFixtureFilter(b2Fixture* fixture);
|
||||||
void Destroy();
|
|
||||||
|
/// \~chinese
|
||||||
private:
|
/// @brief 销毁物体
|
||||||
Actor* actor_;
|
void Destroy();
|
||||||
World* world_;
|
|
||||||
b2Body* body_;
|
private:
|
||||||
|
Actor* actor_;
|
||||||
uint16_t category_bits_;
|
World* world_;
|
||||||
uint16_t mask_bits_;
|
b2Body* body_;
|
||||||
int16_t group_index_;
|
|
||||||
};
|
uint16_t category_bits_;
|
||||||
|
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 bool Body::InitBody(World* world, ActorPtr actor)
|
||||||
inline ContactEdgeList Body::GetContactList() const { KGE_ASSERT(body_); return ContactEdgeList(ContactEdge(body_->GetContactList())); }
|
{
|
||||||
|
return InitBody(world, actor.get());
|
||||||
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_; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,73 +18,73 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano-physics/Contact.h>
|
|
||||||
#include <kiwano-physics/Body.h>
|
#include <kiwano-physics/Body.h>
|
||||||
|
#include <kiwano-physics/Contact.h>
|
||||||
#include <kiwano-physics/World.h>
|
#include <kiwano-physics/World.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
|
|
||||||
Contact::Contact()
|
Contact::Contact()
|
||||||
: contact_(nullptr)
|
: contact_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Contact::Contact(b2Contact* contact)
|
|
||||||
: Contact()
|
|
||||||
{
|
|
||||||
SetB2Contact(contact);
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Contact::GetFixtureA() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(contact_);
|
|
||||||
return Fixture(contact_->GetFixtureA());
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture Contact::GetFixtureB() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(contact_);
|
|
||||||
return Fixture(contact_->GetFixtureB());
|
|
||||||
}
|
|
||||||
|
|
||||||
Body* Contact::GetBodyA() const
|
|
||||||
{
|
|
||||||
return GetFixtureA().GetBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
Body* Contact::GetBodyB() const
|
|
||||||
{
|
|
||||||
return GetFixtureB().GetBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Contact::SetTangentSpeed(float speed)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(contact_);
|
|
||||||
|
|
||||||
Body* body = GetFixtureA().GetBody();
|
|
||||||
KGE_ASSERT(body);
|
|
||||||
|
|
||||||
World* world = body->GetWorld();
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
contact_->SetTangentSpeed(world->Stage2World(speed));
|
|
||||||
}
|
|
||||||
|
|
||||||
float Contact::GetTangentSpeed() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(contact_);
|
|
||||||
|
|
||||||
const Body* body = GetFixtureA().GetBody();
|
|
||||||
KGE_ASSERT(body);
|
|
||||||
|
|
||||||
const World* world = body->GetWorld();
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
return world->World2Stage(contact_->GetTangentSpeed());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Contact::Contact(b2Contact* contact)
|
||||||
|
: Contact()
|
||||||
|
{
|
||||||
|
SetB2Contact(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Contact::GetFixtureA() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(contact_);
|
||||||
|
return Fixture(contact_->GetFixtureA());
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture Contact::GetFixtureB() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(contact_);
|
||||||
|
return Fixture(contact_->GetFixtureB());
|
||||||
|
}
|
||||||
|
|
||||||
|
Body* Contact::GetBodyA() const
|
||||||
|
{
|
||||||
|
return GetFixtureA().GetBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
Body* Contact::GetBodyB() const
|
||||||
|
{
|
||||||
|
return GetFixtureB().GetBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Contact::SetTangentSpeed(float speed)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(contact_);
|
||||||
|
|
||||||
|
Body* body = GetFixtureA().GetBody();
|
||||||
|
KGE_ASSERT(body);
|
||||||
|
|
||||||
|
World* world = body->GetWorld();
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
contact_->SetTangentSpeed(world->Stage2World(speed));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Contact::GetTangentSpeed() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(contact_);
|
||||||
|
|
||||||
|
const Body* body = GetFixtureA().GetBody();
|
||||||
|
KGE_ASSERT(body);
|
||||||
|
|
||||||
|
const World* world = body->GetWorld();
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
return world->World2Stage(contact_->GetTangentSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,232 +19,277 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano-physics/helper.h>
|
|
||||||
#include <kiwano-physics/Fixture.h>
|
#include <kiwano-physics/Fixture.h>
|
||||||
|
#include <kiwano-physics/helper.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
class Body;
|
class Body;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Physics
|
* \addtogroup Physics
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 物理接触
|
/// @brief 物理接触
|
||||||
class KGE_API Contact
|
class KGE_API Contact
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Contact();
|
Contact();
|
||||||
Contact(b2Contact* contact);
|
Contact(b2Contact* contact);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否有效
|
/// @brief 是否有效
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否是接触
|
/// @brief 是否是接触
|
||||||
bool IsTouching() const;
|
bool IsTouching() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 启用或禁用 (仅作用于一个时间步)
|
/// @brief 启用或禁用 (仅作用于一个时间步)
|
||||||
void SetEnabled(bool flag);
|
void SetEnabled(bool flag);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否启用
|
/// @brief 是否启用
|
||||||
bool IsEnabled() const;
|
bool IsEnabled() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取物体A的夹具
|
/// @brief 获取物体A的夹具
|
||||||
Fixture GetFixtureA() const;
|
Fixture GetFixtureA() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取物体B的夹具
|
/// @brief 获取物体B的夹具
|
||||||
Fixture GetFixtureB() const;
|
Fixture GetFixtureB() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取物体A
|
/// @brief 获取物体A
|
||||||
Body* GetBodyA() const;
|
Body* GetBodyA() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取物体B
|
/// @brief 获取物体B
|
||||||
Body* GetBodyB() const;
|
Body* GetBodyB() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置摩擦力
|
/// @brief 设置摩擦力
|
||||||
void SetFriction(float friction);
|
void SetFriction(float friction);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取摩擦力
|
/// @brief 获取摩擦力
|
||||||
float GetFriction() const;
|
float GetFriction() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 重置摩擦力
|
/// @brief 重置摩擦力
|
||||||
void ResetFriction();
|
void ResetFriction();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置弹性恢复
|
/// @brief 设置弹性恢复
|
||||||
void SetRestitution(float restitution);
|
void SetRestitution(float restitution);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取弹性恢复
|
/// @brief 获取弹性恢复
|
||||||
float GetRestitution() const;
|
float GetRestitution() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 重置弹性恢复
|
/// @brief 重置弹性恢复
|
||||||
void ResetRestitution();
|
void ResetRestitution();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置切线速度
|
/// @brief 设置切线速度
|
||||||
void SetTangentSpeed(float speed);
|
void SetTangentSpeed(float speed);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取切线速度
|
/// @brief 获取切线速度
|
||||||
float GetTangentSpeed() const;
|
float GetTangentSpeed() const;
|
||||||
|
|
||||||
b2Contact* GetB2Contact() const;
|
b2Contact* GetB2Contact() const;
|
||||||
void SetB2Contact(b2Contact* contact);
|
void SetB2Contact(b2Contact* contact);
|
||||||
|
|
||||||
bool operator== (const Contact& rhs) const;
|
bool operator==(const Contact& rhs) const;
|
||||||
bool operator!= (const Contact& rhs) const;
|
bool operator!=(const Contact& rhs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
b2Contact* contact_;
|
b2Contact* contact_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \~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>;
|
||||||
|
|
||||||
/// \~chinese
|
public:
|
||||||
/// @brief 物理接触列表
|
IteratorImpl(const _Ty& elem)
|
||||||
class ContactList
|
: elem_(elem)
|
||||||
: 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:
|
inline typename herit::reference operator*() const
|
||||||
IteratorImpl(const _Ty& elem)
|
{
|
||||||
: elem_(elem)
|
return const_cast<typename herit::reference>(elem_);
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
|
||||||
inline typename herit::reference operator*() const
|
inline typename herit::pointer operator->() const
|
||||||
{
|
{
|
||||||
return const_cast<typename herit::reference>(elem_);
|
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline typename herit::pointer operator->() const
|
inline IteratorImpl& operator++()
|
||||||
{
|
{
|
||||||
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
elem_ = elem_.GetB2Contact()->GetNext();
|
||||||
}
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline IteratorImpl& operator++()
|
inline IteratorImpl operator++(int)
|
||||||
{
|
{
|
||||||
elem_ = elem_.GetB2Contact()->GetNext();
|
IteratorImpl old = *this;
|
||||||
return *this;
|
operator++();
|
||||||
}
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
inline IteratorImpl operator++(int)
|
inline bool operator==(const IteratorImpl& rhs) const
|
||||||
{
|
{
|
||||||
IteratorImpl old = *this;
|
return elem_ == rhs.elem_;
|
||||||
operator++();
|
}
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator== (const IteratorImpl& rhs) const
|
inline bool operator!=(const IteratorImpl& rhs) const
|
||||||
{
|
{
|
||||||
return elem_ == rhs.elem_;
|
return !operator==(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!= (const IteratorImpl& rhs) const
|
private:
|
||||||
{
|
_Ty elem_;
|
||||||
return !operator==(rhs);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
public:
|
||||||
_Ty elem_;
|
using value_type = Contact;
|
||||||
};
|
using iterator = IteratorImpl<value_type>;
|
||||||
|
using const_iterator = IteratorImpl<const value_type>;
|
||||||
|
|
||||||
public:
|
inline ContactList() {}
|
||||||
using value_type = Contact;
|
|
||||||
using iterator = IteratorImpl<value_type>;
|
|
||||||
using const_iterator = IteratorImpl<const value_type>;
|
|
||||||
|
|
||||||
inline ContactList()
|
inline ContactList(const value_type& first)
|
||||||
{
|
: first_(first)
|
||||||
}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
inline ContactList(const value_type& first)
|
inline const value_type& front() const
|
||||||
: first_(first)
|
{
|
||||||
{
|
return first_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const value_type& front() const
|
inline value_type& front()
|
||||||
{
|
{
|
||||||
return first_;
|
return first_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline value_type& front()
|
inline iterator begin()
|
||||||
{
|
{
|
||||||
return first_;
|
return iterator(first_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator begin()
|
inline const_iterator begin() const
|
||||||
{
|
{
|
||||||
return iterator(first_);
|
return cbegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator begin() const
|
inline const_iterator cbegin() const
|
||||||
{
|
{
|
||||||
return cbegin();
|
return const_iterator(first_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator cbegin() const
|
inline iterator end()
|
||||||
{
|
{
|
||||||
return const_iterator(first_);
|
return iterator(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator end()
|
inline const_iterator end() const
|
||||||
{
|
{
|
||||||
return iterator(nullptr);
|
return cend();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator end() const
|
inline const_iterator cend() const
|
||||||
{
|
{
|
||||||
return cend();
|
return const_iterator(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator cend() const
|
private:
|
||||||
{
|
value_type first_;
|
||||||
return const_iterator(nullptr);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
/** @} */
|
||||||
value_type first_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
inline bool Contact::IsValid() const
|
||||||
|
{
|
||||||
|
return contact_ != nullptr;
|
||||||
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_; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,19 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
|
|
||||||
ContactEdge::ContactEdge()
|
ContactEdge::ContactEdge()
|
||||||
: edge_(nullptr)
|
: edge_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
ContactEdge::ContactEdge(b2ContactEdge* edge)
|
|
||||||
: ContactEdge()
|
|
||||||
{
|
|
||||||
SetB2ContactEdge(edge);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContactEdge::ContactEdge(b2ContactEdge* edge)
|
||||||
|
: ContactEdge()
|
||||||
|
{
|
||||||
|
SetB2ContactEdge(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,164 +23,183 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \addtogroup Physics
|
* \addtogroup Physics
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 接触边
|
/// @brief 接触边
|
||||||
class KGE_API ContactEdge
|
class KGE_API ContactEdge
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ContactEdge();
|
ContactEdge();
|
||||||
ContactEdge(b2ContactEdge* edge);
|
ContactEdge(b2ContactEdge* edge);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否有效
|
/// @brief 是否有效
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取接触物体
|
/// @brief 获取接触物体
|
||||||
Body* GetOtherBody() const;
|
Body* GetOtherBody() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取接触
|
/// @brief 获取接触
|
||||||
Contact GetContact() const;
|
Contact GetContact() const;
|
||||||
|
|
||||||
b2ContactEdge* GetB2ContactEdge() const;
|
b2ContactEdge* GetB2ContactEdge() const;
|
||||||
void SetB2ContactEdge(b2ContactEdge* edge);
|
void SetB2ContactEdge(b2ContactEdge* edge);
|
||||||
|
|
||||||
bool operator== (const ContactEdge& rhs) const;
|
bool operator==(const ContactEdge& rhs) const;
|
||||||
bool operator!= (const ContactEdge& rhs) const;
|
bool operator!=(const ContactEdge& rhs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
b2ContactEdge* edge_;
|
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>;
|
||||||
|
|
||||||
/// \~chinese
|
public:
|
||||||
/// @brief 物理接触边列表
|
inline IteratorImpl(const _Ty& elem)
|
||||||
class ContactEdgeList
|
: elem_(elem)
|
||||||
{
|
{
|
||||||
template <typename _Ty>
|
}
|
||||||
class IteratorImpl
|
|
||||||
: public std::iterator<std::forward_iterator_tag, _Ty>
|
|
||||||
{
|
|
||||||
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
|
|
||||||
|
|
||||||
public:
|
inline typename herit::reference operator*() const
|
||||||
inline IteratorImpl(const _Ty& elem)
|
{
|
||||||
: elem_(elem)
|
return const_cast<typename herit::reference>(elem_);
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
|
||||||
inline typename herit::reference operator*() const
|
inline typename herit::pointer operator->() const
|
||||||
{
|
{
|
||||||
return const_cast<typename herit::reference>(elem_);
|
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline typename herit::pointer operator->() const
|
inline IteratorImpl& operator++()
|
||||||
{
|
{
|
||||||
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
elem_ = elem_.GetB2ContactEdge()->next;
|
||||||
}
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline IteratorImpl& operator++()
|
inline IteratorImpl operator++(int)
|
||||||
{
|
{
|
||||||
elem_ = elem_.GetB2ContactEdge()->next;
|
IteratorImpl old = *this;
|
||||||
return *this;
|
operator++();
|
||||||
}
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
inline IteratorImpl operator++(int)
|
inline bool operator==(const IteratorImpl& rhs) const
|
||||||
{
|
{
|
||||||
IteratorImpl old = *this;
|
return elem_ == rhs.elem_;
|
||||||
operator++();
|
}
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator== (const IteratorImpl& rhs) const
|
inline bool operator!=(const IteratorImpl& rhs) const
|
||||||
{
|
{
|
||||||
return elem_ == rhs.elem_;
|
return !operator==(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!= (const IteratorImpl& rhs) const
|
private:
|
||||||
{
|
_Ty elem_;
|
||||||
return !operator==(rhs);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
public:
|
||||||
_Ty elem_;
|
using value_type = ContactEdge;
|
||||||
};
|
using iterator = IteratorImpl<value_type>;
|
||||||
|
using const_iterator = IteratorImpl<const value_type>;
|
||||||
|
|
||||||
public:
|
inline ContactEdgeList() {}
|
||||||
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 ContactEdgeList(const value_type& first)
|
inline const value_type& front() const
|
||||||
: first_(first)
|
{
|
||||||
{
|
return first_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const value_type& front() const
|
inline value_type& front()
|
||||||
{
|
{
|
||||||
return first_;
|
return first_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline value_type& front()
|
inline iterator begin()
|
||||||
{
|
{
|
||||||
return first_;
|
return iterator(first_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator begin()
|
inline const_iterator begin() const
|
||||||
{
|
{
|
||||||
return iterator(first_);
|
return cbegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator begin() const
|
inline const_iterator cbegin() const
|
||||||
{
|
{
|
||||||
return cbegin();
|
return const_iterator(first_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator cbegin() const
|
inline iterator end()
|
||||||
{
|
{
|
||||||
return const_iterator(first_);
|
return iterator(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator end()
|
inline const_iterator end() const
|
||||||
{
|
{
|
||||||
return iterator(nullptr);
|
return cend();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator end() const
|
inline const_iterator cend() const
|
||||||
{
|
{
|
||||||
return cend();
|
return const_iterator(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator cend() const
|
private:
|
||||||
{
|
value_type first_;
|
||||||
return const_iterator(nullptr);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
/** @} */
|
||||||
value_type first_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
inline bool ContactEdge::IsValid() const
|
||||||
|
{
|
||||||
inline bool ContactEdge::IsValid() const { return edge_ != nullptr; }
|
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_; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -22,29 +22,29 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
ContactBeginEvent::ContactBeginEvent()
|
ContactBeginEvent::ContactBeginEvent()
|
||||||
: Event(KGE_EVENT(ContactBeginEvent))
|
: Event(KGE_EVENT(ContactBeginEvent))
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
ContactBeginEvent::ContactBeginEvent(Contact const& contact)
|
|
||||||
: ContactBeginEvent()
|
|
||||||
{
|
|
||||||
this->contact = contact;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContactEndEvent::ContactEndEvent()
|
|
||||||
: Event(KGE_EVENT(ContactEndEvent))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ContactEndEvent::ContactEndEvent(Contact const& contact)
|
|
||||||
: ContactEndEvent()
|
|
||||||
{
|
|
||||||
this->contact = contact;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContactBeginEvent::ContactBeginEvent(Contact const& contact)
|
||||||
|
: ContactBeginEvent()
|
||||||
|
{
|
||||||
|
this->contact = contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContactEndEvent::ContactEndEvent()
|
||||||
|
: Event(KGE_EVENT(ContactEndEvent))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactEndEvent::ContactEndEvent(Contact const& contact)
|
||||||
|
: ContactEndEvent()
|
||||||
|
{
|
||||||
|
this->contact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,44 +19,45 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano-physics/Contact.h>
|
|
||||||
#include <kiwano-physics/Body.h>
|
#include <kiwano-physics/Body.h>
|
||||||
|
#include <kiwano-physics/Contact.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
/**
|
KGE_DECLARE_SMART_PTR(ContactBeginEvent);
|
||||||
* \addtogroup Events
|
KGE_DECLARE_SMART_PTR(ContactEndEvent);
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// \~chinese
|
/**
|
||||||
/// @brief 物理接触开始事件
|
* \addtogroup Events
|
||||||
class KGE_API ContactBeginEvent
|
* @{
|
||||||
: public Event
|
*/
|
||||||
{
|
|
||||||
public:
|
|
||||||
Contact contact; ///< 产生的接触
|
|
||||||
|
|
||||||
ContactBeginEvent();
|
/// \~chinese
|
||||||
|
/// @brief 物理接触开始事件
|
||||||
|
class KGE_API ContactBeginEvent : public Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Contact contact; ///< 产生的接触
|
||||||
|
|
||||||
ContactBeginEvent(Contact const& contact);
|
ContactBeginEvent();
|
||||||
};
|
|
||||||
|
|
||||||
/// \~chinese
|
ContactBeginEvent(Contact const& contact);
|
||||||
/// @brief 物理接触结束事件
|
};
|
||||||
class KGE_API ContactEndEvent
|
|
||||||
: public Event
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Contact contact; ///< 产生的接触
|
|
||||||
|
|
||||||
ContactEndEvent();
|
/// \~chinese
|
||||||
|
/// @brief 物理接触结束事件
|
||||||
|
class KGE_API ContactEndEvent : public Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Contact contact; ///< 产生的接触
|
||||||
|
|
||||||
ContactEndEvent(Contact const& contact);
|
ContactEndEvent();
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
ContactEndEvent(Contact const& contact);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
/** @} */
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,88 +18,91 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano-physics/Fixture.h>
|
|
||||||
#include <kiwano-physics/Body.h>
|
#include <kiwano-physics/Body.h>
|
||||||
|
#include <kiwano-physics/Fixture.h>
|
||||||
#include <kiwano-physics/World.h>
|
#include <kiwano-physics/World.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
|
|
||||||
Fixture::Fixture()
|
Fixture::Fixture()
|
||||||
: fixture_(nullptr)
|
: fixture_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Fixture::Fixture(b2Fixture* fixture)
|
|
||||||
: Fixture()
|
|
||||||
{
|
|
||||||
SetB2Fixture(fixture);
|
|
||||||
}
|
|
||||||
|
|
||||||
Fixture::Fixture(Body* body, Shape* shape, const Param& param)
|
|
||||||
: Fixture()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(body);
|
|
||||||
|
|
||||||
if (shape)
|
|
||||||
{
|
|
||||||
shape->FitWorld(body->GetWorld());
|
|
||||||
|
|
||||||
b2Body* b2body = body->GetB2Body();
|
|
||||||
b2FixtureDef fd;
|
|
||||||
fd.density = param.density;
|
|
||||||
fd.friction = param.friction;
|
|
||||||
fd.restitution = param.restitution;
|
|
||||||
fd.shape = shape->GetB2Shape();
|
|
||||||
auto fixture = b2body->CreateFixture(&fd);
|
|
||||||
SetB2Fixture(fixture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Body* Fixture::GetBody() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(fixture_);
|
|
||||||
return static_cast<Body*>(fixture_->GetBody()->GetUserData());
|
|
||||||
}
|
|
||||||
|
|
||||||
Shape Fixture::GetShape() const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(fixture_);
|
|
||||||
return Shape(fixture_->GetShape());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fixture::GetMassData(float* mass, Point* center, float* inertia) const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(fixture_);
|
|
||||||
|
|
||||||
const Body* body = GetBody();
|
|
||||||
KGE_ASSERT(body);
|
|
||||||
|
|
||||||
const World* world = body->GetWorld();
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
b2MassData data;
|
|
||||||
fixture_->GetMassData(&data);
|
|
||||||
|
|
||||||
if (mass) *mass = data.mass;
|
|
||||||
if (center) *center = world->World2Stage(data.center);
|
|
||||||
if (inertia) *inertia = data.I;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Fixture::TestPoint(const Point& p) const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(fixture_);
|
|
||||||
|
|
||||||
const Body* body = GetBody();
|
|
||||||
KGE_ASSERT(body);
|
|
||||||
|
|
||||||
const World* world = body->GetWorld();
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
return fixture_->TestPoint(world->Stage2World(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fixture::Fixture(b2Fixture* fixture)
|
||||||
|
: Fixture()
|
||||||
|
{
|
||||||
|
SetB2Fixture(fixture);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixture::Fixture(Body* body, Shape* shape, const Param& param)
|
||||||
|
: Fixture()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(body);
|
||||||
|
|
||||||
|
if (shape)
|
||||||
|
{
|
||||||
|
shape->FitWorld(body->GetWorld());
|
||||||
|
|
||||||
|
b2Body* b2body = body->GetB2Body();
|
||||||
|
b2FixtureDef fd;
|
||||||
|
fd.density = param.density;
|
||||||
|
fd.friction = param.friction;
|
||||||
|
fd.restitution = param.restitution;
|
||||||
|
fd.shape = shape->GetB2Shape();
|
||||||
|
auto fixture = b2body->CreateFixture(&fd);
|
||||||
|
SetB2Fixture(fixture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Body* Fixture::GetBody() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(fixture_);
|
||||||
|
return static_cast<Body*>(fixture_->GetBody()->GetUserData());
|
||||||
|
}
|
||||||
|
|
||||||
|
Shape Fixture::GetShape() const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(fixture_);
|
||||||
|
return Shape(fixture_->GetShape());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fixture::GetMassData(float* mass, Point* center, float* inertia) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(fixture_);
|
||||||
|
|
||||||
|
const Body* body = GetBody();
|
||||||
|
KGE_ASSERT(body);
|
||||||
|
|
||||||
|
const World* world = body->GetWorld();
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
b2MassData data;
|
||||||
|
fixture_->GetMassData(&data);
|
||||||
|
|
||||||
|
if (mass)
|
||||||
|
*mass = data.mass;
|
||||||
|
if (center)
|
||||||
|
*center = world->World2Stage(data.center);
|
||||||
|
if (inertia)
|
||||||
|
*inertia = data.I;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Fixture::TestPoint(const Point& p) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(fixture_);
|
||||||
|
|
||||||
|
const Body* body = GetBody();
|
||||||
|
KGE_ASSERT(body);
|
||||||
|
|
||||||
|
const World* world = body->GetWorld();
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
return fixture_->TestPoint(world->Stage2World(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,237 +19,281 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano-physics/helper.h>
|
|
||||||
#include <kiwano-physics/Shape.h>
|
#include <kiwano-physics/Shape.h>
|
||||||
|
#include <kiwano-physics/helper.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
class Body;
|
class Body;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Physics
|
* \addtogroup Physics
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 物理夹具
|
/// @brief 物理夹具
|
||||||
class Fixture
|
class Fixture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 夹具参数
|
/// @brief 夹具参数
|
||||||
struct Param
|
struct Param
|
||||||
{
|
{
|
||||||
float density = 0.f; ///< 密度
|
float density = 0.f; ///< 密度
|
||||||
float friction = 0.2f; ///< 摩擦力
|
float friction = 0.2f; ///< 摩擦力
|
||||||
float restitution = 0.f; ///< 弹性恢复
|
float restitution = 0.f; ///< 弹性恢复
|
||||||
bool is_sensor = false; ///< 是否是接触传感器
|
bool is_sensor = false; ///< 是否是接触传感器
|
||||||
|
|
||||||
Param() {}
|
Param() {}
|
||||||
|
|
||||||
Param(float density, float friction = 0.2f, float restitution = 0.f, bool is_sensor = false)
|
Param(float density, float friction = 0.2f, float restitution = 0.f, bool is_sensor = false)
|
||||||
: density(density)
|
: density(density)
|
||||||
, friction(friction)
|
, friction(friction)
|
||||||
, restitution(restitution)
|
, restitution(restitution)
|
||||||
, is_sensor(is_sensor)
|
, is_sensor(is_sensor)
|
||||||
{}
|
{
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Fixture();
|
Fixture();
|
||||||
Fixture(b2Fixture* fixture);
|
Fixture(b2Fixture* fixture);
|
||||||
Fixture(Body* body, Shape* shape, const Param& param);
|
Fixture(Body* body, Shape* shape, const Param& param);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否有效
|
/// @brief 是否有效
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取夹具所在的物体
|
/// @brief 获取夹具所在的物体
|
||||||
Body* GetBody() const;
|
Body* GetBody() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 形状
|
/// @brief 形状
|
||||||
Shape GetShape() const;
|
Shape GetShape() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否是接触传感器
|
/// @brief 是否是接触传感器
|
||||||
bool IsSensor() const;
|
bool IsSensor() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置夹具是否是接触传感器
|
/// @brief 设置夹具是否是接触传感器
|
||||||
/// @details 接触传感器只会产生物理接触,而不会影响物体运动
|
/// @details 接触传感器只会产生物理接触,而不会影响物体运动
|
||||||
void SetSensor(bool sensor);
|
void SetSensor(bool sensor);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取夹具的质量数据
|
/// @brief 获取夹具的质量数据
|
||||||
void GetMassData(float* mass, Point* center, float* inertia) const;
|
void GetMassData(float* mass, Point* center, float* inertia) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取密度
|
/// @brief 获取密度
|
||||||
float GetDensity() const;
|
float GetDensity() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置密度
|
/// @brief 设置密度
|
||||||
void SetDensity(float density);
|
void SetDensity(float density);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取摩擦力 [N]
|
/// @brief 获取摩擦力 [N]
|
||||||
float GetFriction() const;
|
float GetFriction() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置摩擦力 [N]
|
/// @brief 设置摩擦力 [N]
|
||||||
void SetFriction(float friction);
|
void SetFriction(float friction);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取弹性恢复
|
/// @brief 获取弹性恢复
|
||||||
float GetRestitution() const;
|
float GetRestitution() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置弹性恢复
|
/// @brief 设置弹性恢复
|
||||||
void SetRestitution(float restitution);
|
void SetRestitution(float restitution);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 点测试
|
/// @brief 点测试
|
||||||
bool TestPoint(const Point& p) const;
|
bool TestPoint(const Point& p) const;
|
||||||
|
|
||||||
b2Fixture* GetB2Fixture() const;
|
b2Fixture* GetB2Fixture() const;
|
||||||
void SetB2Fixture(b2Fixture* fixture);
|
void SetB2Fixture(b2Fixture* fixture);
|
||||||
|
|
||||||
bool operator== (const Fixture& rhs) const;
|
bool operator==(const Fixture& rhs) const;
|
||||||
bool operator!= (const Fixture& rhs) const;
|
bool operator!=(const Fixture& rhs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
b2Fixture* fixture_;
|
b2Fixture* fixture_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 物理夹具列表
|
/// @brief 物理夹具列表
|
||||||
class FixtureList
|
class FixtureList : public List<Fixture>
|
||||||
: public List<Fixture>
|
{
|
||||||
{
|
template <typename _Ty>
|
||||||
template <typename _Ty>
|
class IteratorImpl : public std::iterator<std::forward_iterator_tag, _Ty>
|
||||||
class IteratorImpl
|
{
|
||||||
: public std::iterator<std::forward_iterator_tag, _Ty>
|
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
|
||||||
{
|
|
||||||
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IteratorImpl(const _Ty& elem)
|
IteratorImpl(const _Ty& elem)
|
||||||
: elem_(elem)
|
: elem_(elem)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline typename herit::reference operator*() const
|
inline typename herit::reference operator*() const
|
||||||
{
|
{
|
||||||
return const_cast<typename herit::reference>(elem_);
|
return const_cast<typename herit::reference>(elem_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline typename herit::pointer operator->() const
|
inline typename herit::pointer operator->() const
|
||||||
{
|
{
|
||||||
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IteratorImpl& operator++()
|
inline IteratorImpl& operator++()
|
||||||
{
|
{
|
||||||
elem_ = elem_.GetB2Fixture()->GetNext();
|
elem_ = elem_.GetB2Fixture()->GetNext();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IteratorImpl operator++(int)
|
inline IteratorImpl operator++(int)
|
||||||
{
|
{
|
||||||
IteratorImpl old = *this;
|
IteratorImpl old = *this;
|
||||||
operator++();
|
operator++();
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator== (const IteratorImpl& rhs) const
|
inline bool operator==(const IteratorImpl& rhs) const
|
||||||
{
|
{
|
||||||
return elem_ == rhs.elem_;
|
return elem_ == rhs.elem_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator!= (const IteratorImpl& rhs) const
|
inline bool operator!=(const IteratorImpl& rhs) const
|
||||||
{
|
{
|
||||||
return !operator==(rhs);
|
return !operator==(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
_Ty elem_;
|
_Ty elem_;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = Fixture;
|
using value_type = Fixture;
|
||||||
using iterator = IteratorImpl<value_type>;
|
using iterator = IteratorImpl<value_type>;
|
||||||
using const_iterator = IteratorImpl<const value_type>;
|
using const_iterator = IteratorImpl<const value_type>;
|
||||||
|
|
||||||
inline FixtureList()
|
inline FixtureList() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FixtureList(const value_type& first)
|
inline FixtureList(const value_type& first)
|
||||||
: first_(first)
|
: first_(first)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const value_type& front() const
|
inline const value_type& front() const
|
||||||
{
|
{
|
||||||
return first_;
|
return first_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline value_type& front()
|
inline value_type& front()
|
||||||
{
|
{
|
||||||
return first_;
|
return first_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator begin()
|
inline iterator begin()
|
||||||
{
|
{
|
||||||
return iterator(first_);
|
return iterator(first_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator begin() const
|
inline const_iterator begin() const
|
||||||
{
|
{
|
||||||
return cbegin();
|
return cbegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator cbegin() const
|
inline const_iterator cbegin() const
|
||||||
{
|
{
|
||||||
return const_iterator(first_);
|
return const_iterator(first_);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator end()
|
inline iterator end()
|
||||||
{
|
{
|
||||||
return iterator(nullptr);
|
return iterator(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator end() const
|
inline const_iterator end() const
|
||||||
{
|
{
|
||||||
return cend();
|
return cend();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const_iterator cend() const
|
inline const_iterator cend() const
|
||||||
{
|
{
|
||||||
return const_iterator(nullptr);
|
return const_iterator(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type first_;
|
value_type first_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline bool Fixture::IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); }
|
inline bool Fixture::IsSensor() const
|
||||||
inline void Fixture::SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); }
|
{
|
||||||
inline float Fixture::GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); }
|
KGE_ASSERT(fixture_);
|
||||||
inline void Fixture::SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); }
|
return fixture_->IsSensor();
|
||||||
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_; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -23,200 +23,200 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
Shape::Shape()
|
Shape::Shape()
|
||||||
: shape_(nullptr)
|
: shape_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Shape::Shape(b2Shape* shape)
|
|
||||||
: shape_(shape)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
b2Shape* Shape::GetB2Shape() const
|
|
||||||
{
|
|
||||||
return shape_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shape::SetB2Shape(b2Shape* shape)
|
|
||||||
{
|
|
||||||
shape_ = shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// CircleShape
|
|
||||||
//
|
|
||||||
|
|
||||||
CircleShape::CircleShape()
|
|
||||||
: Shape(&circle_)
|
|
||||||
, circle_()
|
|
||||||
, radius_(0.f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CircleShape::CircleShape(float radius, Point const& offset)
|
|
||||||
: CircleShape()
|
|
||||||
{
|
|
||||||
Set(radius, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CircleShape::Set(float radius, Point const& offset)
|
|
||||||
{
|
|
||||||
radius_ = radius;
|
|
||||||
offset_ = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CircleShape::FitWorld(World* world)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
circle_.m_radius = world->Stage2World(radius_);
|
|
||||||
circle_.m_p = world->Stage2World(offset_);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// BoxShape
|
|
||||||
//
|
|
||||||
|
|
||||||
BoxShape::BoxShape()
|
|
||||||
: Shape(&polygon_)
|
|
||||||
, polygon_()
|
|
||||||
, rotation_(0.f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxShape::BoxShape(Vec2 const& size, Point const& offset, float rotation)
|
|
||||||
: BoxShape()
|
|
||||||
{
|
|
||||||
Set(size, offset, rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BoxShape::Set(Vec2 const& size, Point const& offset, float rotation)
|
|
||||||
{
|
|
||||||
box_size_ = size;
|
|
||||||
offset_ = offset;
|
|
||||||
rotation_ = rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BoxShape::FitWorld(World* world)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
b2Vec2 box = world->Stage2World(box_size_);
|
|
||||||
b2Vec2 offset = world->Stage2World(offset_);
|
|
||||||
polygon_.SetAsBox(box.x / 2, box.y / 2, offset, rotation_);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// PolygonShape
|
|
||||||
//
|
|
||||||
|
|
||||||
PolygonShape::PolygonShape()
|
|
||||||
: Shape(&polygon_)
|
|
||||||
, polygon_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PolygonShape::PolygonShape(Vector<Point> const& vertexs)
|
|
||||||
: PolygonShape()
|
|
||||||
{
|
|
||||||
Set(vertexs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PolygonShape::Set(Vector<Point> const& vertexs)
|
|
||||||
{
|
|
||||||
vertexs_ = vertexs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PolygonShape::FitWorld(World* world)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
Vector<b2Vec2> b2vertexs;
|
|
||||||
b2vertexs.reserve(vertexs_.size());
|
|
||||||
for (const auto& v : vertexs_)
|
|
||||||
{
|
|
||||||
b2vertexs.push_back(world->Stage2World(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
polygon_.Set(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// EdgeShape
|
|
||||||
//
|
|
||||||
|
|
||||||
EdgeShape::EdgeShape()
|
|
||||||
: Shape(&edge_)
|
|
||||||
, edge_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeShape::EdgeShape(Point const& p1, Point const& p2)
|
|
||||||
: EdgeShape()
|
|
||||||
{
|
|
||||||
Set(p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EdgeShape::Set(Point const& p1, Point const& p2)
|
|
||||||
{
|
|
||||||
p_[0] = p1;
|
|
||||||
p_[1] = p2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EdgeShape::FitWorld(World* world)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
b2Vec2 p1 = world->Stage2World(p_[0]);
|
|
||||||
b2Vec2 p2 = world->Stage2World(p_[1]);
|
|
||||||
edge_.Set(p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ChainShape
|
|
||||||
//
|
|
||||||
|
|
||||||
ChainShape::ChainShape()
|
|
||||||
: Shape(&chain_)
|
|
||||||
, chain_()
|
|
||||||
, loop_(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ChainShape::ChainShape(Vector<Point> const& vertexs, bool loop)
|
|
||||||
: ChainShape()
|
|
||||||
{
|
|
||||||
Set(vertexs, loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChainShape::Set(Vector<Point> const& vertexs, bool loop)
|
|
||||||
{
|
|
||||||
vertexs_ = vertexs;
|
|
||||||
loop_ = loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChainShape::FitWorld(World* world)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(world);
|
|
||||||
|
|
||||||
Vector<b2Vec2> b2vertexs;
|
|
||||||
b2vertexs.reserve(vertexs_.size());
|
|
||||||
for (const auto& v : vertexs_)
|
|
||||||
{
|
|
||||||
b2vertexs.push_back(world->Stage2World(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loop_)
|
|
||||||
{
|
|
||||||
chain_.CreateLoop(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chain_.CreateChain(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shape::Shape(b2Shape* shape)
|
||||||
|
: shape_(shape)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b2Shape* Shape::GetB2Shape() const
|
||||||
|
{
|
||||||
|
return shape_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shape::SetB2Shape(b2Shape* shape)
|
||||||
|
{
|
||||||
|
shape_ = shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// CircleShape
|
||||||
|
//
|
||||||
|
|
||||||
|
CircleShape::CircleShape()
|
||||||
|
: Shape(&circle_)
|
||||||
|
, circle_()
|
||||||
|
, radius_(0.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CircleShape::CircleShape(float radius, Point const& offset)
|
||||||
|
: CircleShape()
|
||||||
|
{
|
||||||
|
Set(radius, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircleShape::Set(float radius, Point const& offset)
|
||||||
|
{
|
||||||
|
radius_ = radius;
|
||||||
|
offset_ = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircleShape::FitWorld(World* world)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
circle_.m_radius = world->Stage2World(radius_);
|
||||||
|
circle_.m_p = world->Stage2World(offset_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BoxShape
|
||||||
|
//
|
||||||
|
|
||||||
|
BoxShape::BoxShape()
|
||||||
|
: Shape(&polygon_)
|
||||||
|
, polygon_()
|
||||||
|
, rotation_(0.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxShape::BoxShape(Vec2 const& size, Point const& offset, float rotation)
|
||||||
|
: BoxShape()
|
||||||
|
{
|
||||||
|
Set(size, offset, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShape::Set(Vec2 const& size, Point const& offset, float rotation)
|
||||||
|
{
|
||||||
|
box_size_ = size;
|
||||||
|
offset_ = offset;
|
||||||
|
rotation_ = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShape::FitWorld(World* world)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
b2Vec2 box = world->Stage2World(box_size_);
|
||||||
|
b2Vec2 offset = world->Stage2World(offset_);
|
||||||
|
polygon_.SetAsBox(box.x / 2, box.y / 2, offset, rotation_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PolygonShape
|
||||||
|
//
|
||||||
|
|
||||||
|
PolygonShape::PolygonShape()
|
||||||
|
: Shape(&polygon_)
|
||||||
|
, polygon_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PolygonShape::PolygonShape(Vector<Point> const& vertexs)
|
||||||
|
: PolygonShape()
|
||||||
|
{
|
||||||
|
Set(vertexs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolygonShape::Set(Vector<Point> const& vertexs)
|
||||||
|
{
|
||||||
|
vertexs_ = vertexs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolygonShape::FitWorld(World* world)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
Vector<b2Vec2> b2vertexs;
|
||||||
|
b2vertexs.reserve(vertexs_.size());
|
||||||
|
for (const auto& v : vertexs_)
|
||||||
|
{
|
||||||
|
b2vertexs.push_back(world->Stage2World(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
polygon_.Set(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// EdgeShape
|
||||||
|
//
|
||||||
|
|
||||||
|
EdgeShape::EdgeShape()
|
||||||
|
: Shape(&edge_)
|
||||||
|
, edge_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeShape::EdgeShape(Point const& p1, Point const& p2)
|
||||||
|
: EdgeShape()
|
||||||
|
{
|
||||||
|
Set(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgeShape::Set(Point const& p1, Point const& p2)
|
||||||
|
{
|
||||||
|
p_[0] = p1;
|
||||||
|
p_[1] = p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgeShape::FitWorld(World* world)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
b2Vec2 p1 = world->Stage2World(p_[0]);
|
||||||
|
b2Vec2 p2 = world->Stage2World(p_[1]);
|
||||||
|
edge_.Set(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ChainShape
|
||||||
|
//
|
||||||
|
|
||||||
|
ChainShape::ChainShape()
|
||||||
|
: Shape(&chain_)
|
||||||
|
, chain_()
|
||||||
|
, loop_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ChainShape::ChainShape(Vector<Point> const& vertexs, bool loop)
|
||||||
|
: ChainShape()
|
||||||
|
{
|
||||||
|
Set(vertexs, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChainShape::Set(Vector<Point> const& vertexs, bool loop)
|
||||||
|
{
|
||||||
|
vertexs_ = vertexs;
|
||||||
|
loop_ = loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChainShape::FitWorld(World* world)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(world);
|
||||||
|
|
||||||
|
Vector<b2Vec2> b2vertexs;
|
||||||
|
b2vertexs.reserve(vertexs_.size());
|
||||||
|
for (const auto& v : vertexs_)
|
||||||
|
{
|
||||||
|
b2vertexs.push_back(world->Stage2World(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop_)
|
||||||
|
{
|
||||||
|
chain_.CreateLoop(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chain_.CreateChain(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,140 +23,135 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
class World;
|
class World;
|
||||||
class Fixture;
|
class Fixture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Physics
|
* \addtogroup Physics
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 形状基类
|
/// @brief 形状基类
|
||||||
class KGE_API Shape
|
class KGE_API Shape
|
||||||
{
|
{
|
||||||
friend class Fixture;
|
friend class Fixture;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Shape();
|
Shape();
|
||||||
Shape(b2Shape* shape);
|
Shape(b2Shape* shape);
|
||||||
|
|
||||||
b2Shape* GetB2Shape() const;
|
b2Shape* GetB2Shape() const;
|
||||||
void SetB2Shape(b2Shape* shape);
|
void SetB2Shape(b2Shape* shape);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void FitWorld(World* world) {}
|
virtual void FitWorld(World* world) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
b2Shape* shape_;
|
b2Shape* shape_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 圆形形状
|
/// @brief 圆形形状
|
||||||
class KGE_API CircleShape
|
class KGE_API CircleShape : public Shape
|
||||||
: public Shape
|
{
|
||||||
{
|
public:
|
||||||
public:
|
CircleShape();
|
||||||
CircleShape();
|
|
||||||
|
|
||||||
CircleShape(float radius, Point const& offset = Point());
|
CircleShape(float radius, Point const& offset = Point());
|
||||||
|
|
||||||
void Set(float radius, Point const& offset = Point());
|
void Set(float radius, Point const& offset = Point());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FitWorld(World* world) override;
|
void FitWorld(World* world) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float radius_;
|
float radius_;
|
||||||
Point offset_;
|
Point offset_;
|
||||||
b2CircleShape circle_;
|
b2CircleShape circle_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 盒子形状
|
/// @brief 盒子形状
|
||||||
class KGE_API BoxShape
|
class KGE_API BoxShape : public Shape
|
||||||
: public Shape
|
{
|
||||||
{
|
public:
|
||||||
public:
|
BoxShape();
|
||||||
BoxShape();
|
|
||||||
|
|
||||||
BoxShape(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
|
BoxShape(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
|
||||||
|
|
||||||
void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
|
void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FitWorld(World* world) override;
|
void FitWorld(World* world) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float rotation_;
|
float rotation_;
|
||||||
Vec2 box_size_;
|
Vec2 box_size_;
|
||||||
Point offset_;
|
Point offset_;
|
||||||
b2PolygonShape polygon_;
|
b2PolygonShape polygon_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 多边形形状
|
/// @brief 多边形形状
|
||||||
class KGE_API PolygonShape
|
class KGE_API PolygonShape : public Shape
|
||||||
: public Shape
|
{
|
||||||
{
|
public:
|
||||||
public:
|
PolygonShape();
|
||||||
PolygonShape();
|
|
||||||
|
|
||||||
PolygonShape(Vector<Point> const& vertexs);
|
PolygonShape(Vector<Point> const& vertexs);
|
||||||
|
|
||||||
void Set(Vector<Point> const& vertexs);
|
void Set(Vector<Point> const& vertexs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FitWorld(World* world) override;
|
void FitWorld(World* world) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<Point> vertexs_;
|
Vector<Point> vertexs_;
|
||||||
b2PolygonShape polygon_;
|
b2PolygonShape polygon_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 线段形状, 用于表示一条边
|
/// @brief 线段形状, 用于表示一条边
|
||||||
class KGE_API EdgeShape
|
class KGE_API EdgeShape : public Shape
|
||||||
: public Shape
|
{
|
||||||
{
|
public:
|
||||||
public:
|
EdgeShape();
|
||||||
EdgeShape();
|
|
||||||
|
|
||||||
EdgeShape(Point const& p1, Point const& p2);
|
EdgeShape(Point const& p1, Point const& p2);
|
||||||
|
|
||||||
void Set(Point const& p1, Point const& p2);
|
void Set(Point const& p1, Point const& p2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FitWorld(World* world) override;
|
void FitWorld(World* world) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Point p_[2];
|
Point p_[2];
|
||||||
b2EdgeShape edge_;
|
b2EdgeShape edge_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 链式形状
|
/// @brief 链式形状
|
||||||
class KGE_API ChainShape
|
class KGE_API ChainShape : public Shape
|
||||||
: public Shape
|
{
|
||||||
{
|
public:
|
||||||
public:
|
ChainShape();
|
||||||
ChainShape();
|
|
||||||
|
|
||||||
ChainShape(Vector<Point> const& vertexs, bool loop = false);
|
ChainShape(Vector<Point> const& vertexs, bool loop = false);
|
||||||
|
|
||||||
void Set(Vector<Point> const& vertexs, bool loop = false);
|
void Set(Vector<Point> const& vertexs, bool loop = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FitWorld(World* world) override;
|
void FitWorld(World* world) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool loop_;
|
bool loop_;
|
||||||
Vector<Point> vertexs_;
|
Vector<Point> vertexs_;
|
||||||
b2ChainShape chain_;
|
b2ChainShape chain_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
} // namespace physics
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,235 +19,237 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
|
|
||||||
#include <kiwano-physics/ContactEvent.h>
|
#include <kiwano-physics/ContactEvent.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const float default_global_scale = 100.f; // 100 pixels per meters
|
const float default_global_scale = 100.f; // 100 pixels per meters
|
||||||
}
|
|
||||||
|
|
||||||
class World::DestructionListener : public b2DestructionListener
|
|
||||||
{
|
|
||||||
World* world_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DestructionListener(World* world)
|
|
||||||
: world_(world)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SayGoodbye(b2Joint* joint) override
|
|
||||||
{
|
|
||||||
if (world_)
|
|
||||||
{
|
|
||||||
world_->JointRemoved(joint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SayGoodbye(b2Fixture* fixture) override
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class World::ContactListener
|
|
||||||
: public b2ContactListener
|
|
||||||
{
|
|
||||||
World* world_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ContactListener(World* world)
|
|
||||||
: world_(world)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeginContact(b2Contact* contact) override
|
|
||||||
{
|
|
||||||
ContactBeginEvent evt(contact);
|
|
||||||
world_->Dispatch(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndContact(b2Contact* contact) override
|
|
||||||
{
|
|
||||||
ContactEndEvent evt(contact);
|
|
||||||
world_->Dispatch(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override { KGE_NOT_USED(contact); KGE_NOT_USED(oldManifold); }
|
|
||||||
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) override { KGE_NOT_USED(contact); KGE_NOT_USED(impulse); }
|
|
||||||
};
|
|
||||||
|
|
||||||
World::World()
|
|
||||||
: world_(b2Vec2(0, 10.0f))
|
|
||||||
, vel_iter_(6)
|
|
||||||
, pos_iter_(2)
|
|
||||||
, global_scale_(default_global_scale)
|
|
||||||
, destruction_listener_(nullptr)
|
|
||||||
, contact_listener_(nullptr)
|
|
||||||
, removing_joint_(false)
|
|
||||||
{
|
|
||||||
destruction_listener_ = new DestructionListener(this);
|
|
||||||
world_.SetDestructionListener(destruction_listener_);
|
|
||||||
|
|
||||||
contact_listener_ = new ContactListener(this);
|
|
||||||
world_.SetContactListener(contact_listener_);
|
|
||||||
}
|
|
||||||
|
|
||||||
World::~World()
|
|
||||||
{
|
|
||||||
world_.SetDestructionListener(nullptr);
|
|
||||||
if (destruction_listener_)
|
|
||||||
{
|
|
||||||
delete destruction_listener_;
|
|
||||||
destruction_listener_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
world_.SetContactListener(nullptr);
|
|
||||||
if (contact_listener_)
|
|
||||||
{
|
|
||||||
delete contact_listener_;
|
|
||||||
contact_listener_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure b2World was destroyed after b2Body
|
|
||||||
RemoveAllChildren();
|
|
||||||
RemoveAllBodies();
|
|
||||||
RemoveAllJoints();
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::RemoveBody(Body* body)
|
|
||||||
{
|
|
||||||
if (body && body->GetB2Body())
|
|
||||||
{
|
|
||||||
world_.DestroyBody(body->GetB2Body());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::RemoveAllBodies()
|
|
||||||
{
|
|
||||||
if (world_.GetBodyCount())
|
|
||||||
{
|
|
||||||
b2Body* body = world_.GetBodyList();
|
|
||||||
while (body)
|
|
||||||
{
|
|
||||||
b2Body* next = body->GetNext();
|
|
||||||
world_.DestroyBody(body);
|
|
||||||
body = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::AddJoint(Joint* joint)
|
|
||||||
{
|
|
||||||
if (joint)
|
|
||||||
{
|
|
||||||
joints_.push_back(joint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::RemoveJoint(Joint* joint)
|
|
||||||
{
|
|
||||||
if (joint)
|
|
||||||
{
|
|
||||||
auto iter = std::find(joints_.begin(), joints_.end(), joint);
|
|
||||||
if (iter != joints_.end())
|
|
||||||
{
|
|
||||||
joints_.erase(iter);
|
|
||||||
|
|
||||||
if (joint->GetB2Joint())
|
|
||||||
{
|
|
||||||
removing_joint_ = true;
|
|
||||||
world_.DestroyJoint(joint->GetB2Joint());
|
|
||||||
removing_joint_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::RemoveAllJoints()
|
|
||||||
{
|
|
||||||
if (world_.GetJointCount())
|
|
||||||
{
|
|
||||||
removing_joint_ = true;
|
|
||||||
{
|
|
||||||
b2Joint* joint = world_.GetJointList();
|
|
||||||
while (joint)
|
|
||||||
{
|
|
||||||
b2Joint* next = joint->GetNext();
|
|
||||||
world_.DestroyJoint(joint);
|
|
||||||
joint = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removing_joint_ = false;
|
|
||||||
}
|
|
||||||
joints_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::JointRemoved(b2Joint* joint)
|
|
||||||
{
|
|
||||||
if (!removing_joint_ && joint)
|
|
||||||
{
|
|
||||||
auto iter = std::find_if(
|
|
||||||
joints_.begin(),
|
|
||||||
joints_.end(),
|
|
||||||
[joint](Joint* j) -> bool { return j->GetB2Joint() == joint; }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (iter != joints_.end())
|
|
||||||
{
|
|
||||||
joints_.erase(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b2World* World::GetB2World()
|
|
||||||
{
|
|
||||||
return &world_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const b2World* World::GetB2World() const
|
|
||||||
{
|
|
||||||
return &world_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 World::GetGravity() const
|
|
||||||
{
|
|
||||||
b2Vec2 g = world_.GetGravity();
|
|
||||||
return Vec2(g.x, g.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::SetGravity(Vec2 gravity)
|
|
||||||
{
|
|
||||||
world_.SetGravity(b2Vec2(gravity.x, gravity.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
ContactList World::GetContactList()
|
|
||||||
{
|
|
||||||
return ContactList(Contact(world_.GetContactList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::Update(Duration dt)
|
|
||||||
{
|
|
||||||
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
|
|
||||||
|
|
||||||
b2Body* b2body = world_.GetBodyList();
|
|
||||||
while (b2body)
|
|
||||||
{
|
|
||||||
Body* body = static_cast<Body*>(b2body->GetUserData());
|
|
||||||
if (body && body->GetType() != Body::Type::Static)
|
|
||||||
{
|
|
||||||
body->UpdateActor();
|
|
||||||
}
|
|
||||||
|
|
||||||
b2body = b2body->GetNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
Stage::Update(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class World::DestructionListener : public b2DestructionListener
|
||||||
|
{
|
||||||
|
World* world_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DestructionListener(World* world)
|
||||||
|
: world_(world)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SayGoodbye(b2Joint* joint) override
|
||||||
|
{
|
||||||
|
if (world_)
|
||||||
|
{
|
||||||
|
world_->JointRemoved(joint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SayGoodbye(b2Fixture* fixture) override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class World::ContactListener : public b2ContactListener
|
||||||
|
{
|
||||||
|
World* world_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ContactListener(World* world)
|
||||||
|
: world_(world)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginContact(b2Contact* contact) override
|
||||||
|
{
|
||||||
|
ContactBeginEventPtr evt = new ContactBeginEvent(contact);
|
||||||
|
world_->DispatchEvent(evt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndContact(b2Contact* contact) override
|
||||||
|
{
|
||||||
|
ContactEndEventPtr evt = new ContactEndEvent(contact);
|
||||||
|
world_->DispatchEvent(evt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override
|
||||||
|
{
|
||||||
|
KGE_NOT_USED(contact);
|
||||||
|
KGE_NOT_USED(oldManifold);
|
||||||
|
}
|
||||||
|
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) override
|
||||||
|
{
|
||||||
|
KGE_NOT_USED(contact);
|
||||||
|
KGE_NOT_USED(impulse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
World::World()
|
||||||
|
: world_(b2Vec2(0, 10.0f))
|
||||||
|
, vel_iter_(6)
|
||||||
|
, pos_iter_(2)
|
||||||
|
, global_scale_(default_global_scale)
|
||||||
|
, destruction_listener_(nullptr)
|
||||||
|
, contact_listener_(nullptr)
|
||||||
|
, removing_joint_(false)
|
||||||
|
{
|
||||||
|
destruction_listener_ = new DestructionListener(this);
|
||||||
|
world_.SetDestructionListener(destruction_listener_);
|
||||||
|
|
||||||
|
contact_listener_ = new ContactListener(this);
|
||||||
|
world_.SetContactListener(contact_listener_);
|
||||||
|
}
|
||||||
|
|
||||||
|
World::~World()
|
||||||
|
{
|
||||||
|
world_.SetDestructionListener(nullptr);
|
||||||
|
if (destruction_listener_)
|
||||||
|
{
|
||||||
|
delete destruction_listener_;
|
||||||
|
destruction_listener_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
world_.SetContactListener(nullptr);
|
||||||
|
if (contact_listener_)
|
||||||
|
{
|
||||||
|
delete contact_listener_;
|
||||||
|
contact_listener_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure b2World was destroyed after b2Body
|
||||||
|
RemoveAllChildren();
|
||||||
|
RemoveAllBodies();
|
||||||
|
RemoveAllJoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::RemoveBody(Body* body)
|
||||||
|
{
|
||||||
|
if (body && body->GetB2Body())
|
||||||
|
{
|
||||||
|
world_.DestroyBody(body->GetB2Body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::RemoveAllBodies()
|
||||||
|
{
|
||||||
|
if (world_.GetBodyCount())
|
||||||
|
{
|
||||||
|
b2Body* body = world_.GetBodyList();
|
||||||
|
while (body)
|
||||||
|
{
|
||||||
|
b2Body* next = body->GetNext();
|
||||||
|
world_.DestroyBody(body);
|
||||||
|
body = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::AddJoint(Joint* joint)
|
||||||
|
{
|
||||||
|
if (joint)
|
||||||
|
{
|
||||||
|
joints_.push_back(joint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::RemoveJoint(Joint* joint)
|
||||||
|
{
|
||||||
|
if (joint)
|
||||||
|
{
|
||||||
|
auto iter = std::find(joints_.begin(), joints_.end(), joint);
|
||||||
|
if (iter != joints_.end())
|
||||||
|
{
|
||||||
|
joints_.erase(iter);
|
||||||
|
|
||||||
|
if (joint->GetB2Joint())
|
||||||
|
{
|
||||||
|
removing_joint_ = true;
|
||||||
|
world_.DestroyJoint(joint->GetB2Joint());
|
||||||
|
removing_joint_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::RemoveAllJoints()
|
||||||
|
{
|
||||||
|
if (world_.GetJointCount())
|
||||||
|
{
|
||||||
|
removing_joint_ = true;
|
||||||
|
{
|
||||||
|
b2Joint* joint = world_.GetJointList();
|
||||||
|
while (joint)
|
||||||
|
{
|
||||||
|
b2Joint* next = joint->GetNext();
|
||||||
|
world_.DestroyJoint(joint);
|
||||||
|
joint = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removing_joint_ = false;
|
||||||
|
}
|
||||||
|
joints_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::JointRemoved(b2Joint* joint)
|
||||||
|
{
|
||||||
|
if (!removing_joint_ && joint)
|
||||||
|
{
|
||||||
|
auto iter = std::find_if(joints_.begin(), joints_.end(),
|
||||||
|
[joint](Joint* j) -> bool { return j->GetB2Joint() == joint; });
|
||||||
|
|
||||||
|
if (iter != joints_.end())
|
||||||
|
{
|
||||||
|
joints_.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b2World* World::GetB2World()
|
||||||
|
{
|
||||||
|
return &world_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b2World* World::GetB2World() const
|
||||||
|
{
|
||||||
|
return &world_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 World::GetGravity() const
|
||||||
|
{
|
||||||
|
b2Vec2 g = world_.GetGravity();
|
||||||
|
return Vec2(g.x, g.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::SetGravity(Vec2 gravity)
|
||||||
|
{
|
||||||
|
world_.SetGravity(b2Vec2(gravity.x, gravity.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactList World::GetContactList()
|
||||||
|
{
|
||||||
|
return ContactList(Contact(world_.GetContactList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::Update(Duration dt)
|
||||||
|
{
|
||||||
|
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
|
||||||
|
|
||||||
|
b2Body* b2body = world_.GetBodyList();
|
||||||
|
while (b2body)
|
||||||
|
{
|
||||||
|
Body* body = static_cast<Body*>(b2body->GetUserData());
|
||||||
|
if (body && body->GetType() != Body::Type::Static)
|
||||||
|
{
|
||||||
|
body->UpdateActor();
|
||||||
|
}
|
||||||
|
|
||||||
|
b2body = b2body->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stage::Update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -24,176 +24,174 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(World);
|
KGE_DECLARE_SMART_PTR(World);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* \defgroup Physics 物理引擎
|
* \defgroup Physics 物理引擎
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Physics
|
* \addtogroup Physics
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 物理世界
|
* @brief 物理世界
|
||||||
*/
|
*/
|
||||||
class KGE_API World
|
class KGE_API World : public Stage
|
||||||
: public Stage
|
{
|
||||||
{
|
friend class Body;
|
||||||
friend class Body;
|
friend class Joint;
|
||||||
friend class Joint;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
World();
|
World();
|
||||||
|
|
||||||
virtual ~World();
|
virtual ~World();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取重力 [N]
|
/// @brief 获取重力 [N]
|
||||||
Vec2 GetGravity() const;
|
Vec2 GetGravity() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置重力 [N]
|
/// @brief 设置重力 [N]
|
||||||
void SetGravity(Vec2 gravity);
|
void SetGravity(Vec2 gravity);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取物理接触列表
|
/// @brief 获取物理接触列表
|
||||||
ContactList GetContactList();
|
ContactList GetContactList();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取全局缩放比例
|
/// @brief 获取全局缩放比例
|
||||||
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100
|
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100
|
||||||
float GetGlobalScale() const;
|
float GetGlobalScale() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置全局缩放比例
|
/// @brief 设置全局缩放比例
|
||||||
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100
|
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100
|
||||||
void SetGlobalScale(float scale);
|
void SetGlobalScale(float scale);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 游戏世界单位转换为物理世界单位
|
/// @brief 游戏世界单位转换为物理世界单位
|
||||||
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
|
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
|
||||||
float World2Stage(float value) const;
|
float World2Stage(float value) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 游戏世界单位转换为物理世界单位
|
/// @brief 游戏世界单位转换为物理世界单位
|
||||||
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
|
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
|
||||||
Vec2 World2Stage(const b2Vec2& pos) const;
|
Vec2 World2Stage(const b2Vec2& pos) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 物理世界单位转换为游戏世界单位
|
/// @brief 物理世界单位转换为游戏世界单位
|
||||||
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
|
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
|
||||||
float Stage2World(float value) const;
|
float Stage2World(float value) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 物理世界单位转换为游戏世界单位
|
/// @brief 物理世界单位转换为游戏世界单位
|
||||||
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
|
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
|
||||||
b2Vec2 Stage2World(const Vec2& pos) const;
|
b2Vec2 Stage2World(const Vec2& pos) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置速度迭代次数, 默认为 6
|
/// @brief 设置速度迭代次数, 默认为 6
|
||||||
void SetVelocityIterations(int vel_iter);
|
void SetVelocityIterations(int vel_iter);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置位置迭代次数, 默认为 2
|
/// @brief 设置位置迭代次数, 默认为 2
|
||||||
void SetPositionIterations(int pos_iter);
|
void SetPositionIterations(int pos_iter);
|
||||||
|
|
||||||
b2World* GetB2World();
|
b2World* GetB2World();
|
||||||
|
|
||||||
const b2World* GetB2World() const;
|
const b2World* GetB2World() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 移除物体
|
/// @brief 移除物体
|
||||||
void RemoveBody(Body* body);
|
void RemoveBody(Body* body);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 移除所有物体
|
/// @brief 移除所有物体
|
||||||
void RemoveAllBodies();
|
void RemoveAllBodies();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加关节
|
/// @brief 添加关节
|
||||||
void AddJoint(Joint* joint);
|
void AddJoint(Joint* joint);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 移除关节
|
/// @brief 移除关节
|
||||||
void RemoveJoint(Joint* joint);
|
void RemoveJoint(Joint* joint);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 移除所有关节
|
/// @brief 移除所有关节
|
||||||
void RemoveAllJoints();
|
void RemoveAllJoints();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 关节被移除
|
/// @brief 关节被移除
|
||||||
void JointRemoved(b2Joint* joint);
|
void JointRemoved(b2Joint* joint);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Update(Duration dt) override;
|
void Update(Duration dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
b2World world_;
|
b2World world_;
|
||||||
int vel_iter_;
|
int vel_iter_;
|
||||||
int pos_iter_;
|
int pos_iter_;
|
||||||
float global_scale_;
|
float global_scale_;
|
||||||
|
|
||||||
class DestructionListener;
|
class DestructionListener;
|
||||||
friend DestructionListener;
|
friend DestructionListener;
|
||||||
DestructionListener* destruction_listener_;
|
DestructionListener* destruction_listener_;
|
||||||
|
|
||||||
class ContactListener;
|
class ContactListener;
|
||||||
friend ContactListener;
|
friend ContactListener;
|
||||||
ContactListener* contact_listener_;
|
ContactListener* contact_listener_;
|
||||||
|
|
||||||
bool removing_joint_;
|
bool removing_joint_;
|
||||||
Vector<Joint*> joints_;
|
Vector<Joint*> joints_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/** @} */
|
inline float World::GetGlobalScale() const
|
||||||
|
{
|
||||||
inline float World::GetGlobalScale() const
|
return global_scale_;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,15 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace physics
|
namespace physics
|
||||||
{
|
{
|
||||||
inline b2Vec2 Stage2World(const Vec2& pos) { return b2Vec2(pos.x, pos.y); }
|
inline b2Vec2 Stage2World(const Vec2& pos)
|
||||||
inline Vec2 World2Stage(const b2Vec2& pos) { return Vec2(pos.x, pos.y); }
|
{
|
||||||
}
|
return b2Vec2(pos.x, pos.y);
|
||||||
}
|
}
|
||||||
|
inline Vec2 World2Stage(const b2Vec2& pos)
|
||||||
|
{
|
||||||
|
return Vec2(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
} // namespace physics
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kiwano-physics/Shape.h>
|
#include <kiwano-physics/Body.h>
|
||||||
#include <kiwano-physics/Fixture.h>
|
|
||||||
#include <kiwano-physics/Contact.h>
|
#include <kiwano-physics/Contact.h>
|
||||||
#include <kiwano-physics/ContactEvent.h>
|
#include <kiwano-physics/ContactEvent.h>
|
||||||
#include <kiwano-physics/Body.h>
|
#include <kiwano-physics/Fixture.h>
|
||||||
#include <kiwano-physics/Joint.h>
|
#include <kiwano-physics/Joint.h>
|
||||||
|
#include <kiwano-physics/Shape.h>
|
||||||
#include <kiwano-physics/World.h>
|
#include <kiwano-physics/World.h>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,207 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <kiwano/2d/Button.h>
|
||||||
|
#include <kiwano/2d/Stage.h>
|
||||||
|
#include <kiwano/platform/Window.h>
|
||||||
|
|
||||||
|
namespace kiwano
|
||||||
|
{
|
||||||
|
Button::Button()
|
||||||
|
: enabled_(true)
|
||||||
|
, status_(Status::Normal)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Button::Button(const Callback& click)
|
||||||
|
: Button()
|
||||||
|
{
|
||||||
|
this->SetClickCallback(click);
|
||||||
|
}
|
||||||
|
|
||||||
|
Button::Button(Callback const& click, Callback const& pressed, Callback const& mouse_over, Callback const& mouse_out)
|
||||||
|
: Button()
|
||||||
|
{
|
||||||
|
this->SetClickCallback(click);
|
||||||
|
this->SetPressedCallback(pressed);
|
||||||
|
this->SetMouseOverCallback(mouse_over);
|
||||||
|
this->SetMouseOutCallback(mouse_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Button::~Button() {}
|
||||||
|
|
||||||
|
bool Button::IsEnable() const
|
||||||
|
{
|
||||||
|
return enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled_ != enabled)
|
||||||
|
{
|
||||||
|
enabled_ = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetClickCallback(const Callback& func)
|
||||||
|
{
|
||||||
|
click_callback_ = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetPressedCallback(const Callback& func)
|
||||||
|
{
|
||||||
|
pressed_callback_ = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetReleasedCallback(const Callback& func)
|
||||||
|
{
|
||||||
|
released_callback_ = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetMouseOverCallback(const Callback& func)
|
||||||
|
{
|
||||||
|
mouse_over_callback_ = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetMouseOutCallback(const Callback& func)
|
||||||
|
{
|
||||||
|
mouse_out_callback_ = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::SetStatus(Status status)
|
||||||
|
{
|
||||||
|
if (status_ != status)
|
||||||
|
{
|
||||||
|
Status old_status = status_;
|
||||||
|
|
||||||
|
if (status == Status::Normal)
|
||||||
|
{
|
||||||
|
Window::Instance().SetCursor(CursorType::Arrow);
|
||||||
|
|
||||||
|
if (mouse_out_callback_)
|
||||||
|
mouse_out_callback_(this);
|
||||||
|
}
|
||||||
|
else if (status == Status::Hover)
|
||||||
|
{
|
||||||
|
Window::Instance().SetCursor(CursorType::Hand);
|
||||||
|
|
||||||
|
if (old_status == Status::Pressed)
|
||||||
|
{
|
||||||
|
if (released_callback_)
|
||||||
|
released_callback_(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mouse_over_callback_)
|
||||||
|
mouse_over_callback_(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (status == Status::Pressed)
|
||||||
|
{
|
||||||
|
if (pressed_callback_)
|
||||||
|
pressed_callback_(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_ = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button::Status Button::GetStatus() const
|
||||||
|
{
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::UpdateStatus(Event* evt)
|
||||||
|
{
|
||||||
|
if (!enabled_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (evt->IsType<MouseHoverEvent>())
|
||||||
|
{
|
||||||
|
SetStatus(Status::Hover);
|
||||||
|
}
|
||||||
|
else if (evt->IsType<MouseOutEvent>())
|
||||||
|
{
|
||||||
|
SetStatus(Status::Normal);
|
||||||
|
}
|
||||||
|
else if (evt->IsType<MouseDownEvent>() && status_ == Status::Hover)
|
||||||
|
{
|
||||||
|
SetStatus(Status::Pressed);
|
||||||
|
}
|
||||||
|
else if (evt->IsType<MouseUpEvent>() && status_ == Status::Pressed)
|
||||||
|
{
|
||||||
|
SetStatus(Status::Hover);
|
||||||
|
}
|
||||||
|
else if (evt->IsType<MouseClickEvent>())
|
||||||
|
{
|
||||||
|
if (click_callback_)
|
||||||
|
click_callback_(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpriteButton::SpriteButton()
|
||||||
|
: SpriteButton(nullptr, nullptr, nullptr, nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SpriteButton::SpriteButton(Callback const& click)
|
||||||
|
: SpriteButton(click, nullptr, nullptr, nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SpriteButton::SpriteButton(Callback const& click, Callback const& pressed, Callback const& mouse_over,
|
||||||
|
Callback const& mouse_out)
|
||||||
|
: Button(click, pressed, mouse_over, mouse_out)
|
||||||
|
{
|
||||||
|
SetResponsible(true);
|
||||||
|
|
||||||
|
EventListener::Callback handler = Closure(this, &SpriteButton::UpdateStatus);
|
||||||
|
AddListener<MouseHoverEvent>(handler);
|
||||||
|
AddListener<MouseOutEvent>(handler);
|
||||||
|
AddListener<MouseDownEvent>(handler);
|
||||||
|
AddListener<MouseUpEvent>(handler);
|
||||||
|
AddListener<MouseClickEvent>(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton::TextButton()
|
||||||
|
: TextButton(nullptr, nullptr, nullptr, nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton::TextButton(Callback const& click)
|
||||||
|
: TextButton(click, nullptr, nullptr, nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton::TextButton(Callback const& click, Callback const& pressed, Callback const& mouse_over,
|
||||||
|
Callback const& mouse_out)
|
||||||
|
: Button(click, pressed, mouse_over, mouse_out)
|
||||||
|
{
|
||||||
|
SetResponsible(true);
|
||||||
|
|
||||||
|
EventListener::Callback handler = Closure(this, &TextButton::UpdateStatus);
|
||||||
|
AddListener<MouseHoverEvent>(handler);
|
||||||
|
AddListener<MouseOutEvent>(handler);
|
||||||
|
AddListener<MouseDownEvent>(handler);
|
||||||
|
AddListener<MouseUpEvent>(handler);
|
||||||
|
AddListener<MouseClickEvent>(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <kiwano/2d/Sprite.h>
|
||||||
|
#include <kiwano/2d/TextActor.h>
|
||||||
|
|
||||||
|
namespace kiwano
|
||||||
|
{
|
||||||
|
KGE_DECLARE_SMART_PTR(Button);
|
||||||
|
KGE_DECLARE_SMART_PTR(SpriteButton);
|
||||||
|
KGE_DECLARE_SMART_PTR(TextButton);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 按钮
|
||||||
|
*/
|
||||||
|
class KGE_API Button : public virtual ObjectBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 按钮回调函数
|
||||||
|
using Callback = Function<void(Button* /* self */)>;
|
||||||
|
|
||||||
|
Button();
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 构造按钮
|
||||||
|
/// @param click 按钮点击回调函数
|
||||||
|
explicit Button(Callback const& click);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 构造按钮
|
||||||
|
/// @param click 按钮点击回调函数
|
||||||
|
/// @param pressed 按钮按下回调函数
|
||||||
|
/// @param mouse_over 按钮移入回调函数
|
||||||
|
/// @param mouse_out 按钮移出回调函数
|
||||||
|
Button(Callback const& click, Callback const& pressed, Callback const& mouse_over, Callback const& mouse_out);
|
||||||
|
|
||||||
|
virtual ~Button();
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取按钮状态是启用还是禁用
|
||||||
|
bool IsEnable() const;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置按钮启用或禁用
|
||||||
|
void SetEnabled(bool enabled);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置按钮点击后的回调函数
|
||||||
|
void SetClickCallback(const Callback& func);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置按钮被按下时的回调函数
|
||||||
|
void SetPressedCallback(const Callback& func);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置按钮被抬起时的回调函数
|
||||||
|
void SetReleasedCallback(const Callback& func);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置鼠标移入按钮时的回调函数
|
||||||
|
void SetMouseOverCallback(const Callback& func);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置鼠标移出按钮时的回调函数
|
||||||
|
void SetMouseOutCallback(const Callback& func);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 按钮状态
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
Normal, ///< 普通
|
||||||
|
Hover, ///< 鼠标在按钮内
|
||||||
|
Pressed ///< 被按下
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 设置按钮状态
|
||||||
|
void SetStatus(Status status);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取按钮状态
|
||||||
|
Status GetStatus() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 更新按钮状态
|
||||||
|
void UpdateStatus(Event* evt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool enabled_;
|
||||||
|
Status status_;
|
||||||
|
Callback click_callback_;
|
||||||
|
Callback pressed_callback_;
|
||||||
|
Callback released_callback_;
|
||||||
|
Callback mouse_over_callback_;
|
||||||
|
Callback mouse_out_callback_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 精灵按钮
|
||||||
|
class SpriteButton
|
||||||
|
: public Sprite
|
||||||
|
, public Button
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SpriteButton();
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 构造精灵按钮
|
||||||
|
/// @param click 按钮点击回调函数
|
||||||
|
explicit SpriteButton(Callback const& click);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 构造精灵按钮
|
||||||
|
/// @param click 按钮点击回调函数
|
||||||
|
/// @param pressed 按钮按下回调函数
|
||||||
|
/// @param mouse_over 按钮移入回调函数
|
||||||
|
/// @param mouse_out 按钮移出回调函数
|
||||||
|
SpriteButton(Callback const& click, Callback const& pressed, Callback const& mouse_over, Callback const& mouse_out);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 文字按钮
|
||||||
|
class TextButton
|
||||||
|
: public TextActor
|
||||||
|
, public Button
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextButton();
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 构造文字按钮
|
||||||
|
/// @param click 按钮点击回调函数
|
||||||
|
explicit TextButton(Callback const& click);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 构造文字按钮
|
||||||
|
/// @param click 按钮点击回调函数
|
||||||
|
/// @param pressed 按钮按下回调函数
|
||||||
|
/// @param mouse_over 按钮移入回调函数
|
||||||
|
/// @param mouse_out 按钮移出回调函数
|
||||||
|
TextButton(Callback const& click, Callback const& pressed, Callback const& mouse_over, Callback const& mouse_out);
|
||||||
|
};
|
||||||
|
} // namespace kiwano
|
||||||
|
|
@ -20,334 +20,291 @@
|
||||||
|
|
||||||
#include <kiwano/2d/Canvas.h>
|
#include <kiwano/2d/Canvas.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Canvas::Canvas()
|
Canvas::Canvas()
|
||||||
: cache_expired_(false)
|
: cache_expired_(false)
|
||||||
, stroke_width_(1.0f)
|
, stroke_width_(1.0f)
|
||||||
, stroke_style_(StrokeStyle::Miter)
|
, stroke_style_()
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Canvas::~Canvas()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::BeginDraw()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->BeginDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::EndDraw()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->EndDraw();
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::OnRender(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
UpdateCache();
|
|
||||||
|
|
||||||
if (texture_cached_ && texture_cached_->IsValid())
|
|
||||||
{
|
|
||||||
PrepareToRender(rt);
|
|
||||||
|
|
||||||
Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight());
|
|
||||||
rt->DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::SetBrush(BrushPtr brush)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(brush);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Canvas::GetStrokeWidth() const
|
|
||||||
{
|
|
||||||
return stroke_width_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::SetBrushTransform(Transform const& transform)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetTransform(transform.ToMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::SetBrushTransform(Matrix3x2 const & transform)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetTransform(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::PushLayerArea(LayerArea& area)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->PushLayer(area);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::PopLayerArea()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->PopLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::PushClipRect(Rect const& clip_rect)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->PushClipRect(clip_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::PopClipRect()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->PopClipRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawLine(Point const& begin, Point const& end)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(stroke_brush_);
|
|
||||||
rt_->DrawLine(
|
|
||||||
begin,
|
|
||||||
end,
|
|
||||||
stroke_width_,
|
|
||||||
stroke_style_
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawCircle(Point const& center, float radius)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(stroke_brush_);
|
|
||||||
rt_->DrawEllipse(
|
|
||||||
center,
|
|
||||||
Vec2(radius, radius),
|
|
||||||
stroke_width_,
|
|
||||||
stroke_style_
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(stroke_brush_);
|
|
||||||
rt_->DrawEllipse(
|
|
||||||
center,
|
|
||||||
radius,
|
|
||||||
stroke_width_,
|
|
||||||
stroke_style_
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawRect(Rect const& rect)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(stroke_brush_);
|
|
||||||
rt_->DrawRectangle(
|
|
||||||
rect,
|
|
||||||
stroke_width_,
|
|
||||||
stroke_style_
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(stroke_brush_);
|
|
||||||
rt_->DrawRoundedRectangle(
|
|
||||||
rect,
|
|
||||||
radius,
|
|
||||||
stroke_width_,
|
|
||||||
stroke_style_
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillCircle(Point const& center, float radius)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(fill_brush_);
|
|
||||||
rt_->FillEllipse(
|
|
||||||
center,
|
|
||||||
Vec2(radius, radius)
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillEllipse(Point const& center, Vec2 const& radius)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(fill_brush_);
|
|
||||||
rt_->FillEllipse(
|
|
||||||
center,
|
|
||||||
radius
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillRect(Rect const& rect)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(fill_brush_);
|
|
||||||
rt_->FillRectangle(
|
|
||||||
rect
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(fill_brush_);
|
|
||||||
rt_->FillRoundedRectangle(
|
|
||||||
rect,
|
|
||||||
radius
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect)
|
|
||||||
{
|
|
||||||
if (texture)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->DrawTexture(*texture, src_rect, dest_rect);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawTextLayout(String const& text, Point const& point)
|
|
||||||
{
|
|
||||||
if (text.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
TextLayout layout;
|
|
||||||
layout.SetStyle(text_style_);
|
|
||||||
layout.SetText(text);
|
|
||||||
DrawTextLayout(layout, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::DrawTextLayout(TextLayout const& layout, Point const& point)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->DrawTextLayout(layout, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::BeginPath(Point const& begin_pos)
|
|
||||||
{
|
|
||||||
geo_sink_.BeginPath(begin_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::EndPath(bool closed)
|
|
||||||
{
|
|
||||||
geo_sink_.EndPath(closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::AddLine(Point const & point)
|
|
||||||
{
|
|
||||||
geo_sink_.AddLine(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::AddLines(Vector<Point> const& points)
|
|
||||||
{
|
|
||||||
geo_sink_.AddLines(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::AddBezier(Point const & point1, Point const & point2, Point const & point3)
|
|
||||||
{
|
|
||||||
geo_sink_.AddBezier(point1, point2, point3);
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(stroke_brush_);
|
|
||||||
rt_->DrawGeometry(
|
|
||||||
geo_sink_.GetGeometry(),
|
|
||||||
stroke_width_,
|
|
||||||
stroke_style_
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillPath()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->SetCurrentBrush(fill_brush_);
|
|
||||||
rt_->FillGeometry(
|
|
||||||
geo_sink_.GetGeometry()
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::Clear()
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->Clear();
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::Clear(Color const& clear_color)
|
|
||||||
{
|
|
||||||
InitRenderTargetAndBrushs();
|
|
||||||
rt_->Clear(clear_color);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_ && rt_)
|
|
||||||
{
|
|
||||||
if (!texture_cached_)
|
|
||||||
{
|
|
||||||
texture_cached_ = new Texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rt_->GetOutput(*texture_cached_))
|
|
||||||
{
|
|
||||||
cache_expired_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Canvas::~Canvas() {}
|
||||||
|
|
||||||
|
void Canvas::BeginDraw()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->BeginDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::EndDraw()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->EndDraw();
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::OnRender(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
UpdateCache();
|
||||||
|
|
||||||
|
if (texture_cached_ && texture_cached_->IsValid())
|
||||||
|
{
|
||||||
|
PrepareToRender(ctx);
|
||||||
|
|
||||||
|
Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight());
|
||||||
|
ctx.DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::SetBrush(BrushPtr brush)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Canvas::GetStrokeWidth() const
|
||||||
|
{
|
||||||
|
return stroke_width_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::SetBrushTransform(Transform const& transform)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetTransform(transform.ToMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::SetBrushTransform(Matrix3x2 const& transform)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::PushLayerArea(LayerArea& area)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->PushLayer(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::PopLayerArea()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->PopLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::PushClipRect(Rect const& clip_rect)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->PushClipRect(clip_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::PopClipRect()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawLine(Point const& begin, Point const& end)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx_->DrawLine(begin, end, stroke_width_, stroke_style_);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawCircle(Point const& center, float radius)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx_->DrawEllipse(center, Vec2(radius, radius), stroke_width_, stroke_style_);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx_->DrawEllipse(center, radius, stroke_width_, stroke_style_);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawRect(Rect const& rect)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx_->DrawRectangle(rect, stroke_width_, stroke_style_);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx_->DrawRoundedRectangle(rect, radius, stroke_width_, stroke_style_);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillCircle(Point const& center, float radius)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(fill_brush_);
|
||||||
|
ctx_->FillEllipse(center, Vec2(radius, radius));
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillEllipse(Point const& center, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(fill_brush_);
|
||||||
|
ctx_->FillEllipse(center, radius);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillRect(Rect const& rect)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(fill_brush_);
|
||||||
|
ctx_->FillRectangle(rect);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(fill_brush_);
|
||||||
|
ctx_->FillRoundedRectangle(rect, radius);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect)
|
||||||
|
{
|
||||||
|
if (texture)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->DrawTexture(*texture, src_rect, dest_rect);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawTextLayout(String const& text, Point const& point)
|
||||||
|
{
|
||||||
|
if (text.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
TextLayout layout;
|
||||||
|
layout.SetStyle(text_style_);
|
||||||
|
layout.SetText(text);
|
||||||
|
DrawTextLayout(layout, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawTextLayout(TextLayout const& layout, Point const& point)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->DrawTextLayout(layout, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::BeginPath(Point const& begin_pos)
|
||||||
|
{
|
||||||
|
geo_sink_.BeginPath(begin_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::EndPath(bool closed)
|
||||||
|
{
|
||||||
|
geo_sink_.EndPath(closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::AddLine(Point const& point)
|
||||||
|
{
|
||||||
|
geo_sink_.AddLine(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::AddLines(Vector<Point> const& points)
|
||||||
|
{
|
||||||
|
geo_sink_.AddLines(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::AddBezier(Point const& point1, Point const& point2, Point const& point3)
|
||||||
|
{
|
||||||
|
geo_sink_.AddBezier(point1, point2, point3);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx_->DrawGeometry(geo_sink_.GetGeometry(), stroke_width_, stroke_style_);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillPath()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->SetCurrentBrush(fill_brush_);
|
||||||
|
ctx_->FillGeometry(geo_sink_.GetGeometry());
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::Clear()
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->Clear();
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::Clear(Color const& clear_color)
|
||||||
|
{
|
||||||
|
InitRenderTargetAndBrushs();
|
||||||
|
ctx_->Clear(clear_color);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexturePtr Canvas::ExportToTexture() const
|
||||||
|
{
|
||||||
|
UpdateCache();
|
||||||
|
return texture_cached_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::InitRenderTargetAndBrushs()
|
||||||
|
{
|
||||||
|
if (!ctx_)
|
||||||
|
{
|
||||||
|
Renderer::Instance().CreateTextureRenderTarget(ctx_);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ && ctx_)
|
||||||
|
{
|
||||||
|
if (!texture_cached_)
|
||||||
|
{
|
||||||
|
texture_cached_ = new Texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx_->GetOutput(*texture_cached_))
|
||||||
|
{
|
||||||
|
cache_expired_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,315 +20,313 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/renderer/RenderTarget.h>
|
#include <kiwano/render/GeometrySink.h>
|
||||||
#include <kiwano/renderer/GeometrySink.h>
|
#include <kiwano/render/RenderContext.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(Canvas);
|
KGE_DECLARE_SMART_PTR(Canvas);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 画布,用于绘制图元
|
* @brief 画布,用于绘制图元
|
||||||
*/
|
*/
|
||||||
class KGE_API Canvas
|
class KGE_API Canvas : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 构建空画布
|
||||||
/// @brief 构建空画布
|
Canvas();
|
||||||
Canvas();
|
|
||||||
|
|
||||||
virtual ~Canvas();
|
virtual ~Canvas();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 开始绘图
|
/// @brief 开始绘图
|
||||||
void BeginDraw();
|
void BeginDraw();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 结束绘图
|
/// @brief 结束绘图
|
||||||
void EndDraw();
|
void EndDraw();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 画线段
|
/// @brief 画线段
|
||||||
/// @param begin 线段起点
|
/// @param begin 线段起点
|
||||||
/// @param end 线段终点
|
/// @param end 线段终点
|
||||||
void DrawLine(Point const& begin, Point const& end);
|
void DrawLine(Point const& begin, Point const& end);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 画圆形边框
|
/// @brief 画圆形边框
|
||||||
/// @param center 圆形原点
|
/// @param center 圆形原点
|
||||||
/// @param radius 圆形半径
|
/// @param radius 圆形半径
|
||||||
void DrawCircle(Point const& center, float radius);
|
void DrawCircle(Point const& center, float radius);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 画椭圆形边框
|
/// @brief 画椭圆形边框
|
||||||
/// @param center 椭圆原点
|
/// @param center 椭圆原点
|
||||||
/// @param radius 椭圆半径
|
/// @param radius 椭圆半径
|
||||||
void DrawEllipse(Point const& center, Vec2 const& radius);
|
void DrawEllipse(Point const& center, Vec2 const& radius);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 画矩形边框
|
/// @brief 画矩形边框
|
||||||
/// @param rect 矩形
|
/// @param rect 矩形
|
||||||
void DrawRect(Rect const& rect);
|
void DrawRect(Rect const& rect);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 画圆角矩形边框
|
/// @brief 画圆角矩形边框
|
||||||
/// @param rect 矩形
|
/// @param rect 矩形
|
||||||
/// @param radius 矩形圆角半径
|
/// @param radius 矩形圆角半径
|
||||||
void DrawRoundedRect(Rect const& rect, Vec2 const& radius);
|
void DrawRoundedRect(Rect const& rect, Vec2 const& radius);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 填充圆形
|
/// @brief 填充圆形
|
||||||
/// @param center 圆形原点
|
/// @param center 圆形原点
|
||||||
/// @param radius 圆形半径
|
/// @param radius 圆形半径
|
||||||
void FillCircle(Point const& center, float radius);
|
void FillCircle(Point const& center, float radius);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 填充椭圆形
|
/// @brief 填充椭圆形
|
||||||
/// @param center 椭圆原点
|
/// @param center 椭圆原点
|
||||||
/// @param radius 椭圆半径
|
/// @param radius 椭圆半径
|
||||||
void FillEllipse(Point const& center, Vec2 const& radius);
|
void FillEllipse(Point const& center, Vec2 const& radius);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 填充矩形
|
/// @brief 填充矩形
|
||||||
/// @param rect 矩形
|
/// @param rect 矩形
|
||||||
void FillRect(Rect const& rect);
|
void FillRect(Rect const& rect);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 填充圆角矩形
|
/// @brief 填充圆角矩形
|
||||||
/// @param rect 矩形
|
/// @param rect 矩形
|
||||||
/// @param radius 矩形圆角半径
|
/// @param radius 矩形圆角半径
|
||||||
void FillRoundedRect(Rect const& rect, Vec2 const& radius);
|
void FillRoundedRect(Rect const& rect, Vec2 const& radius);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 绘制纹理
|
/// @brief 绘制纹理
|
||||||
/// @param texture 纹理
|
/// @param texture 纹理
|
||||||
/// @param src_rect 纹理裁剪区域
|
/// @param src_rect 纹理裁剪区域
|
||||||
/// @param dest_rect 绘制目标区域
|
/// @param dest_rect 绘制目标区域
|
||||||
void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
|
void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 绘制文字布局
|
/// @brief 绘制文字布局
|
||||||
/// @param text 文字
|
/// @param text 文字
|
||||||
/// @param point 绘制文字的位置
|
/// @param point 绘制文字的位置
|
||||||
void DrawTextLayout(String const& text, Point const& point);
|
void DrawTextLayout(String const& text, Point const& point);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 绘制文字布局
|
/// @brief 绘制文字布局
|
||||||
/// @param layout 文字布局
|
/// @param layout 文字布局
|
||||||
/// @param point 绘制布局的位置
|
/// @param point 绘制布局的位置
|
||||||
void DrawTextLayout(TextLayout const& layout, Point const& point);
|
void DrawTextLayout(TextLayout const& layout, Point const& point);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 开始绘制路径
|
/// @brief 开始绘制路径
|
||||||
/// @param begin_pos 路径起始点
|
/// @param begin_pos 路径起始点
|
||||||
void BeginPath(Point const& begin_pos);
|
void BeginPath(Point const& begin_pos);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 结束路径
|
/// @brief 结束路径
|
||||||
/// @param closed 路径是否闭合
|
/// @param closed 路径是否闭合
|
||||||
void EndPath(bool closed = false);
|
void EndPath(bool closed = false);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加一条线段
|
/// @brief 添加一条线段
|
||||||
/// @param point 端点
|
/// @param point 端点
|
||||||
void AddLine(Point const& point);
|
void AddLine(Point const& point);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加多条线段
|
/// @brief 添加多条线段
|
||||||
/// @param points 端点集合
|
/// @param points 端点集合
|
||||||
void AddLines(Vector<Point> const& points);
|
void AddLines(Vector<Point> const& points);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加一条三次方贝塞尔曲线
|
/// @brief 添加一条三次方贝塞尔曲线
|
||||||
/// @param point1 贝塞尔曲线的第一个控制点
|
/// @param point1 贝塞尔曲线的第一个控制点
|
||||||
/// @param point2 贝塞尔曲线的第二个控制点
|
/// @param point2 贝塞尔曲线的第二个控制点
|
||||||
/// @param point3 贝塞尔曲线的终点
|
/// @param point3 贝塞尔曲线的终点
|
||||||
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
|
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加弧线
|
/// @brief 添加弧线
|
||||||
/// @param point 终点
|
/// @param point 终点
|
||||||
/// @param radius 椭圆半径
|
/// @param radius 椭圆半径
|
||||||
/// @param rotation 椭圆旋转角度
|
/// @param rotation 椭圆旋转角度
|
||||||
/// @param clockwise 顺时针 or 逆时针
|
/// @param clockwise 顺时针 or 逆时针
|
||||||
/// @param is_small 是否取小于 180° 的弧
|
/// @param is_small 是否取小于 180° 的弧
|
||||||
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
|
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 以描边的方式绘制路径
|
/// @brief 以描边的方式绘制路径
|
||||||
void StrokePath();
|
void StrokePath();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 以填充的方式绘制路径
|
/// @brief 以填充的方式绘制路径
|
||||||
void FillPath();
|
void FillPath();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 清空画布
|
/// @brief 清空画布
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 清空画布
|
/// @brief 清空画布
|
||||||
/// @param clear_color 清空颜色
|
/// @param clear_color 清空颜色
|
||||||
void Clear(Color const& clear_color);
|
void Clear(Color const& clear_color);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置填充颜色
|
/// @brief 设置填充颜色
|
||||||
/// @param color 填充颜色
|
/// @param color 填充颜色
|
||||||
void SetFillColor(Color const& color);
|
void SetFillColor(Color const& color);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置填充画刷
|
/// @brief 设置填充画刷
|
||||||
/// @param[in] brush 填充画刷
|
/// @param[in] brush 填充画刷
|
||||||
void SetFillBrush(BrushPtr brush);
|
void SetFillBrush(BrushPtr brush);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置轮廓颜色
|
/// @brief 设置轮廓颜色
|
||||||
/// @param color 轮廓颜色
|
/// @param color 轮廓颜色
|
||||||
void SetStrokeColor(Color const& color);
|
void SetStrokeColor(Color const& color);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置轮廓画刷
|
/// @brief 设置轮廓画刷
|
||||||
/// @param[in] brush 轮廓画刷
|
/// @param[in] brush 轮廓画刷
|
||||||
void SetStrokeBrush(BrushPtr brush);
|
void SetStrokeBrush(BrushPtr brush);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置轮廓宽度
|
/// @brief 设置轮廓宽度
|
||||||
/// @param width 轮廓宽度
|
/// @param width 轮廓宽度
|
||||||
void SetStrokeWidth(float width);
|
void SetStrokeWidth(float width);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置轮廓样式
|
/// @brief 设置轮廓样式
|
||||||
/// @param stroke_style 轮廓样式
|
/// @param stroke_style 轮廓样式
|
||||||
void SetStrokeStyle(StrokeStyle stroke_style);
|
void SetStrokeStyle(const StrokeStyle& stroke_style);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字画刷样式
|
/// @brief 设置文字画刷样式
|
||||||
/// @param text_style 文字画刷样式
|
/// @param text_style 文字画刷样式
|
||||||
void SetTextStyle(TextStyle const& text_style);
|
void SetTextStyle(TextStyle const& text_style);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置画刷
|
/// @brief 设置画刷
|
||||||
/// @param[in] brush 画刷
|
/// @param[in] brush 画刷
|
||||||
void SetBrush(BrushPtr brush);
|
void SetBrush(BrushPtr brush);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置画刷二维变换
|
/// @brief 设置画刷二维变换
|
||||||
/// @param transform 二维变换
|
/// @param transform 二维变换
|
||||||
void SetBrushTransform(Transform const& transform);
|
void SetBrushTransform(Transform const& transform);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置画刷二维变换矩阵
|
/// @brief 设置画刷二维变换矩阵
|
||||||
/// @param transform 二维变换矩阵
|
/// @param transform 二维变换矩阵
|
||||||
void SetBrushTransform(Matrix3x2 const& transform);
|
void SetBrushTransform(Matrix3x2 const& transform);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加一个图层
|
/// @brief 添加一个图层
|
||||||
/// @param area 图层区域
|
/// @param area 图层区域
|
||||||
void PushLayerArea(LayerArea& area);
|
void PushLayerArea(LayerArea& area);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 删除最近添加的图层
|
/// @brief 删除最近添加的图层
|
||||||
void PopLayerArea();
|
void PopLayerArea();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加一个裁剪区域
|
/// @brief 添加一个裁剪区域
|
||||||
/// @param clip_rect 裁剪矩形
|
/// @param clip_rect 裁剪矩形
|
||||||
void PushClipRect(Rect const& clip_rect);
|
void PushClipRect(Rect const& clip_rect);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 删除最近添加的裁剪区域
|
/// @brief 删除最近添加的裁剪区域
|
||||||
void PopClipRect();
|
void PopClipRect();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取轮廓宽度
|
/// @brief 获取轮廓宽度
|
||||||
float GetStrokeWidth() const;
|
float GetStrokeWidth() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取填充画刷
|
/// @brief 获取填充画刷
|
||||||
BrushPtr GetFillBrush() const;
|
BrushPtr GetFillBrush() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取轮廓画刷
|
/// @brief 获取轮廓画刷
|
||||||
BrushPtr GetStrokeBrush() const;
|
BrushPtr GetStrokeBrush() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 导出纹理
|
/// @brief 导出纹理
|
||||||
TexturePtr ExportToTexture() const;
|
TexturePtr ExportToTexture() const;
|
||||||
|
|
||||||
void OnRender(RenderTarget* rt) override;
|
void OnRender(RenderContext& ctx) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitRenderTargetAndBrushs();
|
void InitRenderTargetAndBrushs();
|
||||||
|
|
||||||
void UpdateCache() const;
|
void UpdateCache() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float stroke_width_;
|
float stroke_width_;
|
||||||
TextStyle text_style_;
|
TextStyle text_style_;
|
||||||
StrokeStyle stroke_style_;
|
StrokeStyle stroke_style_;
|
||||||
GeometrySink geo_sink_;
|
GeometrySink geo_sink_;
|
||||||
BrushPtr fill_brush_;
|
BrushPtr fill_brush_;
|
||||||
BrushPtr stroke_brush_;
|
BrushPtr stroke_brush_;
|
||||||
|
|
||||||
mutable bool cache_expired_;
|
mutable bool cache_expired_;
|
||||||
mutable TexturePtr texture_cached_;
|
mutable TexturePtr texture_cached_;
|
||||||
mutable TextureRenderTargetPtr rt_;
|
mutable TextureRenderContextPtr ctx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
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_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
inline void Canvas::SetStrokeWidth(float width)
|
||||||
|
{
|
||||||
|
stroke_width_ = std::max(width, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Canvas::SetStrokeStyle(const 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_;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,127 +19,128 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/DebugActor.h>
|
#include <kiwano/2d/DebugActor.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
|
#include <kiwano/render/Renderer.h>
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
|
|
||||||
#pragma comment(lib, "psapi.lib")
|
#pragma comment(lib, "psapi.lib")
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class comma_numpunct : public std::numpunct<wchar_t>
|
class comma_numpunct : public std::numpunct<wchar_t>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
virtual wchar_t do_thousands_sep() const override
|
virtual wchar_t do_thousands_sep() const override
|
||||||
{
|
{
|
||||||
return L',';
|
return L',';
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string do_grouping() const override
|
virtual std::string do_grouping() const override
|
||||||
{
|
{
|
||||||
return "\03";
|
return "\03";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
std::locale comma_locale(std::locale(), new comma_numpunct);
|
DebugActor::DebugActor()
|
||||||
}
|
{
|
||||||
|
SetName(L"kiwano-debug-actor");
|
||||||
|
SetPosition(Point{ 10, 10 });
|
||||||
|
SetResponsible(true);
|
||||||
|
SetCascadeOpacityEnabled(true);
|
||||||
|
|
||||||
DebugActor::DebugActor()
|
comma_locale_ = std::locale(std::locale(), new comma_numpunct);
|
||||||
{
|
|
||||||
SetName(L"kiwano-debug-actor");
|
|
||||||
SetPosition(Point{ 10, 10 });
|
|
||||||
SetResponsible(true);
|
|
||||||
SetCascadeOpacityEnabled(true);
|
|
||||||
|
|
||||||
background_brush_ = new Brush;
|
background_brush_ = new Brush;
|
||||||
background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f));
|
background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f));
|
||||||
|
|
||||||
debug_text_ = new TextActor;
|
BrushPtr fill_brush = new Brush;
|
||||||
debug_text_->SetPosition(Point{ 10, 10 });
|
fill_brush->SetColor(Color::White);
|
||||||
this->AddChild(debug_text_);
|
|
||||||
|
|
||||||
TextStyle style;
|
TextStyle style;
|
||||||
style.font_family = L"Arial";
|
style.font_family = L"Arial";
|
||||||
style.font_size = 16.f;
|
style.font_size = 16.f;
|
||||||
style.font_weight = FontWeight::Normal;
|
style.font_weight = FontWeight::Normal;
|
||||||
style.line_spacing = 20.f;
|
style.line_spacing = 20.f;
|
||||||
debug_text_->SetStyle(style);
|
style.fill_brush = fill_brush;
|
||||||
debug_text_->SetFillColor(Color::White);
|
debug_text_.SetStyle(style);
|
||||||
|
|
||||||
AddListener<MouseHoverEvent>([=](Event&) { SetOpacity(0.4f); });
|
AddListener<MouseHoverEvent>([=](Event*) { SetOpacity(0.4f); });
|
||||||
AddListener<MouseOutEvent>([=](Event&) { SetOpacity(1.f); });
|
AddListener<MouseOutEvent>([=](Event*) { SetOpacity(1.f); });
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugActor::~DebugActor()
|
DebugActor::~DebugActor() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugActor::OnRender(RenderTarget* rt)
|
void DebugActor::OnRender(RenderContext& ctx)
|
||||||
{
|
{
|
||||||
rt->SetCurrentBrush(background_brush_);
|
ctx.SetCurrentBrush(background_brush_);
|
||||||
rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f });
|
ctx.FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f });
|
||||||
}
|
ctx.DrawTextLayout(debug_text_, Point(10, 10));
|
||||||
|
}
|
||||||
|
|
||||||
void DebugActor::OnUpdate(Duration dt)
|
void DebugActor::OnUpdate(Duration dt)
|
||||||
{
|
{
|
||||||
KGE_NOT_USED(dt);
|
KGE_NOT_USED(dt);
|
||||||
|
|
||||||
frame_time_.push_back(Time::Now());
|
frame_time_.push_back(Time::Now());
|
||||||
while (frame_time_.back() - frame_time_.front() >= Duration::Second)
|
while (frame_time_.back() - frame_time_.front() >= Duration::Second)
|
||||||
{
|
{
|
||||||
frame_time_.erase(frame_time_.begin());
|
frame_time_.erase(frame_time_.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
StringStream ss;
|
StringStream ss;
|
||||||
|
|
||||||
// For formatting integers with commas
|
// For formatting integers with commas
|
||||||
(void)ss.imbue(comma_locale);
|
(void)ss.imbue(comma_locale_);
|
||||||
|
|
||||||
ss << "Fps: " << frame_time_.size() << std::endl;
|
ss << "Fps: " << frame_time_.size() << std::endl;
|
||||||
|
|
||||||
#if defined(KGE_DEBUG)
|
#if defined(KGE_DEBUG)
|
||||||
if (ObjectBase::IsTracingLeaks())
|
if (ObjectBase::IsTracingLeaks())
|
||||||
{
|
{
|
||||||
ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl;
|
ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ss << "Render: " << Renderer::instance().GetStatus().duration.Milliseconds() << "ms" << std::endl;
|
ss << "Render: " << Renderer::Instance().GetStatus().duration.Milliseconds() << "ms" << std::endl;
|
||||||
|
|
||||||
ss << "Primitives / sec: " << std::fixed << Renderer::instance().GetStatus().primitives * frame_time_.size() << std::endl;
|
ss << "Primitives / sec: " << std::fixed << Renderer::Instance().GetStatus().primitives * frame_time_.size()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
ss << "Memory: ";
|
ss << "Memory: ";
|
||||||
{
|
{
|
||||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||||
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
|
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
|
||||||
|
|
||||||
if (pmc.PrivateUsage > 1024 * 1024)
|
if (pmc.PrivateUsage > 1024 * 1024)
|
||||||
{
|
{
|
||||||
ss << pmc.PrivateUsage / (1024 * 1024) << "Mb ";
|
ss << pmc.PrivateUsage / (1024 * 1024) << "Mb ";
|
||||||
pmc.PrivateUsage %= (1024 * 1024);
|
pmc.PrivateUsage %= (1024 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << pmc.PrivateUsage / 1024 << "Kb";
|
ss << pmc.PrivateUsage / 1024 << "Kb";
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_text_->SetText(ss.str());
|
debug_text_.SetText(ss.str());
|
||||||
|
debug_text_.Update();
|
||||||
|
|
||||||
if (debug_text_->GetWidth() > GetWidth() - 20)
|
Size layout_size = debug_text_.GetLayoutSize();
|
||||||
{
|
if (layout_size.x > GetWidth() - 20)
|
||||||
SetWidth(20 + debug_text_->GetWidth());
|
{
|
||||||
}
|
SetWidth(20 + layout_size.x);
|
||||||
|
}
|
||||||
if (debug_text_->GetHeight() > GetHeight() - 20)
|
|
||||||
{
|
|
||||||
SetHeight(20 + debug_text_->GetHeight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugActor::CheckVisibilty(RenderTarget* rt) const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (layout_size.y > GetHeight() - 20)
|
||||||
|
{
|
||||||
|
SetHeight(20 + layout_size.y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DebugActor::CheckVisibility(RenderContext& ctx) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,42 +20,39 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/2d/TextActor.h>
|
#include <kiwano/render/TextLayout.h>
|
||||||
#include <kiwano/renderer/Color.h>
|
|
||||||
#include <kiwano/renderer/Brush.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief µ÷ÊÔ½Úµã
|
* @brief µ÷ÊÔ½Úµã
|
||||||
*/
|
*/
|
||||||
class KGE_API DebugActor
|
class KGE_API DebugActor : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
DebugActor();
|
||||||
DebugActor();
|
|
||||||
|
|
||||||
virtual ~DebugActor();
|
virtual ~DebugActor();
|
||||||
|
|
||||||
void OnRender(RenderTarget* rt) override;
|
void OnRender(RenderContext& ctx) override;
|
||||||
|
|
||||||
void OnUpdate(Duration dt) override;
|
void OnUpdate(Duration dt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
bool CheckVisibility(RenderContext& ctx) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BrushPtr background_brush_;
|
std::locale comma_locale_;
|
||||||
TextActorPtr debug_text_;
|
BrushPtr background_brush_;
|
||||||
Vector<Time> frame_time_;
|
TextLayout debug_text_;
|
||||||
};
|
Vector<Time> frame_time_;
|
||||||
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
} // namespace kiwano
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -19,56 +19,54 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/Frame.h>
|
#include <kiwano/2d/Frame.h>
|
||||||
#include <kiwano/renderer/TextureCache.h>
|
#include <kiwano/render/TextureCache.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Frame::Frame()
|
Frame::Frame() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Frame::Load(String const& file_path)
|
bool Frame::Load(String const& file_path)
|
||||||
{
|
{
|
||||||
TexturePtr texture = TextureCache::instance().AddOrGetTexture(file_path);
|
TexturePtr texture = TextureCache::Instance().AddOrGetTexture(file_path);
|
||||||
if (texture->IsValid())
|
if (texture->IsValid())
|
||||||
{
|
{
|
||||||
SetTexture(texture);
|
SetTexture(texture);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
bool Frame::Load(Resource const& res)
|
|
||||||
{
|
|
||||||
TexturePtr texture = TextureCache::instance().AddOrGetTexture(res);
|
|
||||||
if (texture->IsValid())
|
|
||||||
{
|
|
||||||
SetTexture(texture);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Frame::SetCropRect(Rect const& crop_rect)
|
|
||||||
{
|
|
||||||
if (texture_->IsValid())
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
crop_rect_.right_bottom.y = std::min(std::max(crop_rect.right_bottom.y, 0.f), bitmap_size.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Frame::SetTexture(TexturePtr texture)
|
|
||||||
{
|
|
||||||
texture_ = texture;
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Frame::Load(Resource const& res)
|
||||||
|
{
|
||||||
|
TexturePtr texture = TextureCache::Instance().AddOrGetTexture(res);
|
||||||
|
if (texture->IsValid())
|
||||||
|
{
|
||||||
|
SetTexture(texture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frame::SetCropRect(Rect const& crop_rect)
|
||||||
|
{
|
||||||
|
if (texture_->IsValid())
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
crop_rect_.right_bottom.y = std::min(std::max(crop_rect.right_bottom.y, 0.f), bitmap_size.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frame::SetTexture(TexturePtr texture)
|
||||||
|
{
|
||||||
|
texture_ = texture;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,82 +20,102 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/ObjectBase.h>
|
#include <kiwano/core/ObjectBase.h>
|
||||||
#include <kiwano/renderer/Texture.h>
|
#include <kiwano/render/Texture.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(Frame);
|
KGE_DECLARE_SMART_PTR(Frame);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 图像帧
|
* @brief 图像帧
|
||||||
*/
|
*/
|
||||||
class KGE_API Frame
|
class KGE_API Frame : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 构建空图像帧
|
||||||
/// @brief 构建空图像帧
|
Frame();
|
||||||
Frame();
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载图像
|
/// @brief 加载图像
|
||||||
/// @param file_path 图像路径
|
/// @param file_path 图像路径
|
||||||
bool Load(String const& file_path);
|
bool Load(String const& file_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载图像
|
/// @brief 加载图像
|
||||||
/// @param res 图像资源
|
/// @param res 图像资源
|
||||||
bool Load(Resource const& res);
|
bool Load(Resource const& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 裁剪图像帧为矩形
|
/// @brief 裁剪图像帧为矩形
|
||||||
/// @param crop_rect 裁剪矩形定义
|
/// @param crop_rect 裁剪矩形定义
|
||||||
void SetCropRect(Rect const& crop_rect);
|
void SetCropRect(Rect const& crop_rect);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置纹理
|
/// @brief 设置纹理
|
||||||
/// @param texture 纹理
|
/// @param texture 纹理
|
||||||
void SetTexture(TexturePtr texture);
|
void SetTexture(TexturePtr texture);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否有效
|
/// @brief 是否有效
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取宽度
|
/// @brief 获取宽度
|
||||||
float GetWidth() const;
|
float GetWidth() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取高度
|
/// @brief 获取高度
|
||||||
float GetHeight() const;
|
float GetHeight() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取大小
|
/// @brief 获取大小
|
||||||
Size GetSize() const;
|
Size GetSize() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取裁剪位置
|
/// @brief 获取裁剪位置
|
||||||
Point GetCropPoint() const;
|
Point GetCropPoint() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取裁剪矩形
|
/// @brief 获取裁剪矩形
|
||||||
Rect const& GetCropRect() const;
|
Rect const& GetCropRect() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取纹理
|
/// @brief 获取纹理
|
||||||
TexturePtr GetTexture() const;
|
TexturePtr GetTexture() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TexturePtr texture_;
|
TexturePtr texture_;
|
||||||
Rect crop_rect_;
|
Rect crop_rect_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool Frame::IsValid() const { return texture_ && texture_->IsValid(); }
|
inline bool Frame::IsValid() const
|
||||||
inline float Frame::GetWidth() const { return crop_rect_.GetWidth(); }
|
{
|
||||||
inline float Frame::GetHeight() const { return crop_rect_.GetHeight(); }
|
return texture_ && texture_->IsValid();
|
||||||
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_; }
|
|
||||||
}
|
}
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,79 +23,75 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
FrameSequence::FrameSequence()
|
FrameSequence::FrameSequence() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameSequence::FrameSequence(Vector<FramePtr> const& frames)
|
|
||||||
{
|
|
||||||
this->AddFrames(frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameSequence::~FrameSequence()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameSequence::AddFrame(FramePtr frame)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(frame && "FrameSequence::Add failed, NULL pointer exception");
|
|
||||||
|
|
||||||
if (frame)
|
|
||||||
{
|
|
||||||
frames_.push_back(frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameSequence::AddFrames(Vector<FramePtr> const& frames)
|
|
||||||
{
|
|
||||||
if (frames_.empty())
|
|
||||||
frames_ = frames;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frames_.reserve(frames_.size() + frames.size());
|
|
||||||
for (const auto& texture : frames)
|
|
||||||
AddFrame(texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FramePtr FrameSequence::GetFrame(size_t index) const
|
|
||||||
{
|
|
||||||
KGE_ASSERT(index < frames_.size());
|
|
||||||
return frames_[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<FramePtr> const& FrameSequence::GetFrames() const
|
|
||||||
{
|
|
||||||
return frames_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FrameSequence::GetFramesCount() const
|
|
||||||
{
|
|
||||||
return frames_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameSequencePtr FrameSequence::Clone() const
|
|
||||||
{
|
|
||||||
auto frame_seq = new (std::nothrow) FrameSequence;
|
|
||||||
if (frame_seq)
|
|
||||||
{
|
|
||||||
frame_seq->AddFrames(frames_);
|
|
||||||
}
|
|
||||||
return frame_seq;
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameSequencePtr FrameSequence::Reverse() const
|
|
||||||
{
|
|
||||||
auto frame_seq = new (std::nothrow) FrameSequence;
|
|
||||||
if (!frames_.empty())
|
|
||||||
{
|
|
||||||
for (auto iter = frames_.crbegin(), crend = frames_.crend(); iter != crend; ++iter)
|
|
||||||
{
|
|
||||||
if (*iter)
|
|
||||||
frame_seq->AddFrame(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return frame_seq;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
FrameSequence::FrameSequence(Vector<FramePtr> const& frames)
|
||||||
|
{
|
||||||
|
this->AddFrames(frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrameSequence::~FrameSequence() {}
|
||||||
|
|
||||||
|
void FrameSequence::AddFrame(FramePtr frame)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(frame && "FrameSequence::Add failed, NULL pointer exception");
|
||||||
|
|
||||||
|
if (frame)
|
||||||
|
{
|
||||||
|
frames_.push_back(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSequence::AddFrames(Vector<FramePtr> const& frames)
|
||||||
|
{
|
||||||
|
if (frames_.empty())
|
||||||
|
frames_ = frames;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frames_.reserve(frames_.size() + frames.size());
|
||||||
|
for (const auto& texture : frames)
|
||||||
|
AddFrame(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FramePtr FrameSequence::GetFrame(size_t index) const
|
||||||
|
{
|
||||||
|
KGE_ASSERT(index < frames_.size());
|
||||||
|
return frames_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<FramePtr> const& FrameSequence::GetFrames() const
|
||||||
|
{
|
||||||
|
return frames_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FrameSequence::GetFramesCount() const
|
||||||
|
{
|
||||||
|
return frames_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameSequencePtr FrameSequence::Clone() const
|
||||||
|
{
|
||||||
|
auto frame_seq = new (std::nothrow) FrameSequence;
|
||||||
|
if (frame_seq)
|
||||||
|
{
|
||||||
|
frame_seq->AddFrames(frames_);
|
||||||
|
}
|
||||||
|
return frame_seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameSequencePtr FrameSequence::Reverse() const
|
||||||
|
{
|
||||||
|
auto frame_seq = new (std::nothrow) FrameSequence;
|
||||||
|
if (!frames_.empty())
|
||||||
|
{
|
||||||
|
for (auto iter = frames_.crbegin(), crend = frames_.crend(); iter != crend; ++iter)
|
||||||
|
{
|
||||||
|
if (*iter)
|
||||||
|
frame_seq->AddFrame(*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return frame_seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,65 +19,64 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/common.h>
|
|
||||||
#include <kiwano/core/time.h>
|
|
||||||
#include <kiwano/2d/Frame.h>
|
#include <kiwano/2d/Frame.h>
|
||||||
|
#include <kiwano/core/Common.h>
|
||||||
|
#include <kiwano/core/Time.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(FrameSequence);
|
KGE_DECLARE_SMART_PTR(FrameSequence);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 序列帧
|
* @brief 序列帧
|
||||||
*/
|
*/
|
||||||
class KGE_API FrameSequence
|
class KGE_API FrameSequence : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 构建空序列帧
|
||||||
/// @brief 构建空序列帧
|
FrameSequence();
|
||||||
FrameSequence();
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构建序列帧
|
/// @brief 构建序列帧
|
||||||
/// @param frames 图像帧集合
|
/// @param frames 图像帧集合
|
||||||
explicit FrameSequence(Vector<FramePtr> const& frames);
|
explicit FrameSequence(Vector<FramePtr> const& frames);
|
||||||
|
|
||||||
virtual ~FrameSequence();
|
virtual ~FrameSequence();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加关键帧
|
/// @brief 添加关键帧
|
||||||
/// @param frame 图像帧
|
/// @param frame 图像帧
|
||||||
void AddFrame(FramePtr frame);
|
void AddFrame(FramePtr frame);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加多个关键帧
|
/// @brief 添加多个关键帧
|
||||||
/// @param frames 图像帧集合
|
/// @param frames 图像帧集合
|
||||||
void AddFrames(Vector<FramePtr> const& frames);
|
void AddFrames(Vector<FramePtr> const& frames);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取关键帧
|
/// @brief 获取关键帧
|
||||||
/// @param index 图像帧下标
|
/// @param index 图像帧下标
|
||||||
FramePtr GetFrame(size_t index) const;
|
FramePtr GetFrame(size_t index) const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取所有关键帧
|
/// @brief 获取所有关键帧
|
||||||
Vector<FramePtr> const& GetFrames() const;
|
Vector<FramePtr> const& GetFrames() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取关键帧数量
|
/// @brief 获取关键帧数量
|
||||||
size_t GetFramesCount() const;
|
size_t GetFramesCount() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取序列帧的拷贝对象
|
/// @brief 获取序列帧的拷贝对象
|
||||||
FrameSequencePtr Clone() const;
|
FrameSequencePtr Clone() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取序列帧的倒转
|
/// @brief 获取序列帧的倒转
|
||||||
FrameSequencePtr Reverse() const;
|
FrameSequencePtr Reverse() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<FramePtr> frames_;
|
Vector<FramePtr> frames_;
|
||||||
};
|
};
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,225 +19,226 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/GifSprite.h>
|
#include <kiwano/2d/GifSprite.h>
|
||||||
#include <kiwano/renderer/TextureCache.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/TextureCache.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
GifSprite::GifSprite()
|
GifSprite::GifSprite()
|
||||||
: animating_(false)
|
: animating_(false)
|
||||||
, next_index_(0)
|
, next_index_(0)
|
||||||
, total_loop_count_(1)
|
, total_loop_count_(1)
|
||||||
, loop_count_(0)
|
, loop_count_(0)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
bool GifSprite::Load(String const& file_path)
|
|
||||||
{
|
|
||||||
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(file_path);
|
|
||||||
return Load(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GifSprite::Load(Resource const& res)
|
|
||||||
{
|
|
||||||
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(res);
|
|
||||||
return Load(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GifSprite::Load(GifImagePtr gif)
|
|
||||||
{
|
|
||||||
if (gif && gif->IsValid())
|
|
||||||
{
|
|
||||||
gif_ = gif;
|
|
||||||
|
|
||||||
next_index_ = 0;
|
|
||||||
loop_count_ = 0;
|
|
||||||
frame_.disposal_type = GifImage::DisposalType::None;
|
|
||||||
|
|
||||||
SetSize(Size{ static_cast<float>(gif_->GetWidthInPixels()), static_cast<float>(gif_->GetHeightInPixels()) });
|
|
||||||
|
|
||||||
if (!frame_rt_)
|
|
||||||
{
|
|
||||||
Renderer::instance().CreateTextureRenderTarget(frame_rt_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gif_->GetFramesCount() > 0)
|
|
||||||
{
|
|
||||||
ComposeNextFrame();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::OnRender(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
if (frame_to_render_ && CheckVisibilty(rt))
|
|
||||||
{
|
|
||||||
PrepareToRender(rt);
|
|
||||||
|
|
||||||
rt->DrawTexture(*frame_to_render_, &frame_.rect, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::Update(Duration dt)
|
|
||||||
{
|
|
||||||
Actor::Update(dt);
|
|
||||||
|
|
||||||
if (gif_ && gif_->IsValid() && animating_)
|
|
||||||
{
|
|
||||||
frame_elapsed_ += dt;
|
|
||||||
if (frame_.delay <= frame_elapsed_)
|
|
||||||
{
|
|
||||||
frame_.delay -= frame_elapsed_;
|
|
||||||
frame_elapsed_ = 0;
|
|
||||||
ComposeNextFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::SetGifImage(GifImagePtr gif)
|
|
||||||
{
|
|
||||||
gif_ = gif;
|
|
||||||
RestartAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::RestartAnimation()
|
|
||||||
{
|
|
||||||
animating_ = true;
|
|
||||||
next_index_ = 0;
|
|
||||||
loop_count_ = 0;
|
|
||||||
frame_.disposal_type = GifImage::DisposalType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::ComposeNextFrame()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(frame_rt_);
|
|
||||||
KGE_ASSERT(gif_);
|
|
||||||
|
|
||||||
if (frame_rt_->IsValid())
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
DisposeCurrentFrame();
|
|
||||||
OverlayNextFrame();
|
|
||||||
} while (frame_.delay.IsZero() && !IsLastFrame());
|
|
||||||
|
|
||||||
animating_ = (!EndOfAnimation() && gif_->GetFramesCount() > 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::DisposeCurrentFrame()
|
|
||||||
{
|
|
||||||
switch (frame_.disposal_type)
|
|
||||||
{
|
|
||||||
case GifImage::DisposalType::Unknown:
|
|
||||||
case GifImage::DisposalType::None:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GifImage::DisposalType::Background:
|
|
||||||
ClearCurrentFrameArea();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GifImage::DisposalType::Previous:
|
|
||||||
RestoreSavedFrame();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::OverlayNextFrame()
|
|
||||||
{
|
|
||||||
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())
|
|
||||||
{
|
|
||||||
frame_rt_->BeginDraw();
|
|
||||||
|
|
||||||
if (next_index_ == 0)
|
|
||||||
{
|
|
||||||
loop_count_++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame_.texture)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsLastFrame() && loop_cb_)
|
|
||||||
{
|
|
||||||
loop_cb_(loop_count_ - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EndOfAnimation() && done_cb_)
|
|
||||||
{
|
|
||||||
done_cb_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::SaveComposedFrame()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(frame_rt_);
|
|
||||||
|
|
||||||
TexturePtr frame_to_be_saved = new Texture;
|
|
||||||
|
|
||||||
if (frame_rt_->GetOutput(*frame_to_be_saved))
|
|
||||||
{
|
|
||||||
if (!saved_frame_)
|
|
||||||
{
|
|
||||||
saved_frame_ = new Texture;
|
|
||||||
frame_rt_->CreateTexture(*saved_frame_, frame_to_be_saved->GetSizeInPixels(), frame_to_be_saved->GetPixelFormat());
|
|
||||||
}
|
|
||||||
|
|
||||||
saved_frame_->CopyFrom(frame_to_be_saved);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::RestoreSavedFrame()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(frame_rt_);
|
|
||||||
|
|
||||||
if (saved_frame_)
|
|
||||||
{
|
|
||||||
TexturePtr frame_to_copy_to = new Texture;
|
|
||||||
|
|
||||||
if (frame_rt_->GetOutput(*frame_to_copy_to))
|
|
||||||
{
|
|
||||||
frame_to_copy_to->CopyFrom(saved_frame_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::ClearCurrentFrameArea()
|
|
||||||
{
|
|
||||||
KGE_ASSERT(frame_rt_);
|
|
||||||
frame_rt_->BeginDraw();
|
|
||||||
|
|
||||||
frame_rt_->PushClipRect(frame_.rect);
|
|
||||||
frame_rt_->Clear();
|
|
||||||
frame_rt_->PopClipRect();
|
|
||||||
|
|
||||||
return frame_rt_->EndDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GifSprite::Load(String const& file_path)
|
||||||
|
{
|
||||||
|
GifImagePtr image = TextureCache::Instance().AddOrGetGifImage(file_path);
|
||||||
|
return Load(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GifSprite::Load(Resource const& res)
|
||||||
|
{
|
||||||
|
GifImagePtr image = TextureCache::Instance().AddOrGetGifImage(res);
|
||||||
|
return Load(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GifSprite::Load(GifImagePtr gif)
|
||||||
|
{
|
||||||
|
if (gif && gif->IsValid())
|
||||||
|
{
|
||||||
|
gif_ = gif;
|
||||||
|
|
||||||
|
next_index_ = 0;
|
||||||
|
loop_count_ = 0;
|
||||||
|
frame_.disposal_type = GifImage::DisposalType::None;
|
||||||
|
|
||||||
|
SetSize(Size{ static_cast<float>(gif_->GetWidthInPixels()), static_cast<float>(gif_->GetHeightInPixels()) });
|
||||||
|
|
||||||
|
if (!frame_rt_)
|
||||||
|
{
|
||||||
|
Renderer::Instance().CreateTextureRenderTarget(frame_rt_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gif_->GetFramesCount() > 0)
|
||||||
|
{
|
||||||
|
ComposeNextFrame();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::OnRender(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
if (frame_to_render_ && CheckVisibility(ctx))
|
||||||
|
{
|
||||||
|
PrepareToRender(ctx);
|
||||||
|
|
||||||
|
ctx.DrawTexture(*frame_to_render_, &frame_.rect, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::Update(Duration dt)
|
||||||
|
{
|
||||||
|
Actor::Update(dt);
|
||||||
|
|
||||||
|
if (gif_ && gif_->IsValid() && animating_)
|
||||||
|
{
|
||||||
|
frame_elapsed_ += dt;
|
||||||
|
if (frame_.delay <= frame_elapsed_)
|
||||||
|
{
|
||||||
|
frame_.delay -= frame_elapsed_;
|
||||||
|
frame_elapsed_ = 0;
|
||||||
|
ComposeNextFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::SetGifImage(GifImagePtr gif)
|
||||||
|
{
|
||||||
|
gif_ = gif;
|
||||||
|
RestartAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::RestartAnimation()
|
||||||
|
{
|
||||||
|
animating_ = true;
|
||||||
|
next_index_ = 0;
|
||||||
|
loop_count_ = 0;
|
||||||
|
frame_.disposal_type = GifImage::DisposalType::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::ComposeNextFrame()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(frame_rt_);
|
||||||
|
KGE_ASSERT(gif_);
|
||||||
|
|
||||||
|
if (frame_rt_->IsValid())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
DisposeCurrentFrame();
|
||||||
|
OverlayNextFrame();
|
||||||
|
} while (frame_.delay.IsZero() && !IsLastFrame());
|
||||||
|
|
||||||
|
animating_ = (!EndOfAnimation() && gif_->GetFramesCount() > 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::DisposeCurrentFrame()
|
||||||
|
{
|
||||||
|
switch (frame_.disposal_type)
|
||||||
|
{
|
||||||
|
case GifImage::DisposalType::Unknown:
|
||||||
|
case GifImage::DisposalType::None:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GifImage::DisposalType::Background:
|
||||||
|
ClearCurrentFrameArea();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GifImage::DisposalType::Previous:
|
||||||
|
RestoreSavedFrame();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::OverlayNextFrame()
|
||||||
|
{
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
frame_rt_->BeginDraw();
|
||||||
|
|
||||||
|
if (next_index_ == 0)
|
||||||
|
{
|
||||||
|
loop_count_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_.texture)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsLastFrame() && loop_cb_)
|
||||||
|
{
|
||||||
|
loop_cb_(loop_count_ - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EndOfAnimation() && done_cb_)
|
||||||
|
{
|
||||||
|
done_cb_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::SaveComposedFrame()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(frame_rt_);
|
||||||
|
|
||||||
|
TexturePtr frame_to_be_saved = new Texture;
|
||||||
|
|
||||||
|
if (frame_rt_->GetOutput(*frame_to_be_saved))
|
||||||
|
{
|
||||||
|
if (!saved_frame_)
|
||||||
|
{
|
||||||
|
saved_frame_ = new Texture;
|
||||||
|
frame_rt_->CreateTexture(*saved_frame_, frame_to_be_saved->GetSizeInPixels(),
|
||||||
|
frame_to_be_saved->GetPixelFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
saved_frame_->CopyFrom(frame_to_be_saved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::RestoreSavedFrame()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(frame_rt_);
|
||||||
|
|
||||||
|
if (saved_frame_)
|
||||||
|
{
|
||||||
|
TexturePtr frame_to_copy_to = new Texture;
|
||||||
|
|
||||||
|
if (frame_rt_->GetOutput(*frame_to_copy_to))
|
||||||
|
{
|
||||||
|
frame_to_copy_to->CopyFrom(saved_frame_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::ClearCurrentFrameArea()
|
||||||
|
{
|
||||||
|
KGE_ASSERT(frame_rt_);
|
||||||
|
frame_rt_->BeginDraw();
|
||||||
|
|
||||||
|
frame_rt_->PushClipRect(frame_.rect);
|
||||||
|
frame_rt_->Clear();
|
||||||
|
frame_rt_->PopClipRect();
|
||||||
|
|
||||||
|
return frame_rt_->EndDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -21,150 +21,173 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/core/Resource.h>
|
#include <kiwano/core/Resource.h>
|
||||||
#include <kiwano/renderer/RenderTarget.h>
|
#include <kiwano/render/GifImage.h>
|
||||||
#include <kiwano/renderer/GifImage.h>
|
#include <kiwano/render/RenderContext.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(GifSprite);
|
KGE_DECLARE_SMART_PTR(GifSprite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief GIF 精灵
|
* @brief GIF 精灵
|
||||||
*/
|
*/
|
||||||
class KGE_API GifSprite
|
class KGE_API GifSprite : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief GIF播放循环结束回调
|
||||||
/// @brief GIF播放循环结束回调
|
using LoopDoneCallback = Function<void(int /* times */)>;
|
||||||
using LoopDoneCallback = Function<void(int /* times */)>;
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief GIF播放结束回调
|
/// @brief GIF播放结束回调
|
||||||
using DoneCallback = Function<void()>;
|
using DoneCallback = Function<void()>;
|
||||||
|
|
||||||
GifSprite();
|
GifSprite();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载GIF图片
|
/// @brief 加载GIF图片
|
||||||
/// @param file_path GIF图片路径
|
/// @param file_path GIF图片路径
|
||||||
bool Load(String const& file_path);
|
bool Load(String const& file_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载GIF图片
|
/// @brief 加载GIF图片
|
||||||
/// @param res GIF图片资源
|
/// @param res GIF图片资源
|
||||||
bool Load(Resource const& res);
|
bool Load(Resource const& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载GIF图片
|
/// @brief 加载GIF图片
|
||||||
/// @param gif GIF图片
|
/// @param gif GIF图片
|
||||||
bool Load(GifImagePtr gif);
|
bool Load(GifImagePtr gif);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置 GIF 动画循环次数
|
/// @brief 设置 GIF 动画循环次数
|
||||||
void SetLoopCount(int loops);
|
void SetLoopCount(int loops);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置 GIF 动画每次循环结束回调函数
|
/// @brief 设置 GIF 动画每次循环结束回调函数
|
||||||
void SetLoopDoneCallback(LoopDoneCallback const& cb);
|
void SetLoopDoneCallback(LoopDoneCallback const& cb);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置 GIF 动画结束回调函数
|
/// @brief 设置 GIF 动画结束回调函数
|
||||||
void SetDoneCallback(DoneCallback const& cb);
|
void SetDoneCallback(DoneCallback const& cb);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置 GIF 图像
|
/// @brief 设置 GIF 图像
|
||||||
void SetGifImage(GifImagePtr gif);
|
void SetGifImage(GifImagePtr gif);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 重新播放 GIF 动画
|
/// @brief 重新播放 GIF 动画
|
||||||
void RestartAnimation();
|
void RestartAnimation();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取 GIF 动画循环结束回调
|
/// @brief 获取 GIF 动画循环结束回调
|
||||||
LoopDoneCallback GetLoopDoneCallback() const;
|
LoopDoneCallback GetLoopDoneCallback() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取 GIF 动画播放结束回调
|
/// @brief 获取 GIF 动画播放结束回调
|
||||||
DoneCallback GetDoneCallback() const;
|
DoneCallback GetDoneCallback() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取 GIF 图片
|
/// @brief 获取 GIF 图片
|
||||||
GifImagePtr GetGifImage() const;
|
GifImagePtr GetGifImage() const;
|
||||||
|
|
||||||
void OnRender(RenderTarget* rt) override;
|
void OnRender(RenderContext& ctx) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Update(Duration dt) override;
|
void Update(Duration dt) override;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否是最后一帧
|
/// @brief 是否是最后一帧
|
||||||
bool IsLastFrame() const;
|
bool IsLastFrame() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画是否已结束
|
/// @brief 动画是否已结束
|
||||||
bool EndOfAnimation() const;
|
bool EndOfAnimation() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 合成下一帧
|
/// @brief 合成下一帧
|
||||||
void ComposeNextFrame();
|
void ComposeNextFrame();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 解析当前图像帧
|
/// @brief 解析当前图像帧
|
||||||
void DisposeCurrentFrame();
|
void DisposeCurrentFrame();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 覆盖下一帧
|
/// @brief 覆盖下一帧
|
||||||
void OverlayNextFrame();
|
void OverlayNextFrame();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 保存合成后的图像帧
|
/// @brief 保存合成后的图像帧
|
||||||
void SaveComposedFrame();
|
void SaveComposedFrame();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 恢复已保存的图像帧
|
/// @brief 恢复已保存的图像帧
|
||||||
void RestoreSavedFrame();
|
void RestoreSavedFrame();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 清空当前图像区域
|
/// @brief 清空当前图像区域
|
||||||
void ClearCurrentFrameArea();
|
void ClearCurrentFrameArea();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool animating_;
|
bool animating_;
|
||||||
int total_loop_count_;
|
int total_loop_count_;
|
||||||
int loop_count_;
|
int loop_count_;
|
||||||
size_t next_index_;
|
size_t next_index_;
|
||||||
Duration frame_elapsed_;
|
Duration frame_elapsed_;
|
||||||
LoopDoneCallback loop_cb_;
|
LoopDoneCallback loop_cb_;
|
||||||
DoneCallback done_cb_;
|
DoneCallback done_cb_;
|
||||||
GifImagePtr gif_;
|
GifImagePtr gif_;
|
||||||
GifImage::Frame frame_;
|
GifImage::Frame frame_;
|
||||||
TexturePtr saved_frame_;
|
TexturePtr saved_frame_;
|
||||||
TexturePtr frame_to_render_;
|
TexturePtr frame_to_render_;
|
||||||
TextureRenderTargetPtr frame_rt_;
|
TextureRenderContextPtr frame_rt_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline void GifSprite::SetLoopCount(int loops) { total_loop_count_ = loops; }
|
inline void GifSprite::SetLoopCount(int loops)
|
||||||
|
{
|
||||||
inline void GifSprite::SetLoopDoneCallback(LoopDoneCallback const& cb) { loop_cb_ = cb; }
|
total_loop_count_ = loops;
|
||||||
|
|
||||||
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; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,71 +20,63 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Layer.h>
|
#include <kiwano/2d/Layer.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Layer::Layer()
|
Layer::Layer()
|
||||||
: swallow_(false)
|
: swallow_(false)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Layer::~Layer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::SetClipRect(Rect const& clip_rect)
|
|
||||||
{
|
|
||||||
area_.SetAreaRect(clip_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::SetOpacity(float opacity)
|
|
||||||
{
|
|
||||||
// Actor::SetOpacity(opacity);
|
|
||||||
area_.SetOpacity(opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::SetMaskGeometry(Geometry const& mask)
|
|
||||||
{
|
|
||||||
area_.SetMaskGeometry(mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::SetMaskTransform(Matrix3x2 const& transform)
|
|
||||||
{
|
|
||||||
area_.SetMaskTransform(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::Dispatch(Event& evt)
|
|
||||||
{
|
|
||||||
if (!IsVisible())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!swallow_)
|
|
||||||
{
|
|
||||||
ActorPtr prev;
|
|
||||||
for (auto child = GetAllChildren().last_item(); child; child = prev)
|
|
||||||
{
|
|
||||||
prev = child->prev_item();
|
|
||||||
child->Dispatch(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EventDispatcher::Dispatch(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::Render(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
rt->PushLayer(area_);
|
|
||||||
|
|
||||||
Actor::Render(rt);
|
|
||||||
|
|
||||||
rt->PopLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Layer::CheckVisibilty(RenderTarget* rt) const
|
|
||||||
{
|
|
||||||
// Do not need to render Layer
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Layer::~Layer() {}
|
||||||
|
|
||||||
|
void Layer::SetClipRect(Rect const& clip_rect)
|
||||||
|
{
|
||||||
|
area_.SetAreaRect(clip_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::SetOpacity(float opacity)
|
||||||
|
{
|
||||||
|
// Actor::SetOpacity(opacity);
|
||||||
|
area_.SetOpacity(opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::SetMaskGeometry(Geometry const& mask)
|
||||||
|
{
|
||||||
|
area_.SetMaskGeometry(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::SetMaskTransform(Matrix3x2 const& transform)
|
||||||
|
{
|
||||||
|
area_.SetMaskTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Layer::DispatchEvent(Event* evt)
|
||||||
|
{
|
||||||
|
if (!IsVisible())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (swallow_)
|
||||||
|
{
|
||||||
|
return EventDispatcher::DispatchEvent(evt);
|
||||||
|
}
|
||||||
|
return Actor::DispatchEvent(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::Render(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
ctx.PushLayer(area_);
|
||||||
|
|
||||||
|
Actor::Render(ctx);
|
||||||
|
|
||||||
|
ctx.PopLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Layer::CheckVisibility(RenderContext& ctx) const
|
||||||
|
{
|
||||||
|
// Do not need to render Layer
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,88 +20,98 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/renderer/LayerArea.h>
|
#include <kiwano/render/LayerArea.h>
|
||||||
#include <kiwano/renderer/RenderTarget.h>
|
#include <kiwano/render/RenderContext.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(Layer);
|
KGE_DECLARE_SMART_PTR(Layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 图层
|
* @brief 图层
|
||||||
*/
|
*/
|
||||||
class KGE_API Layer
|
class KGE_API Layer : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
Layer();
|
||||||
Layer();
|
|
||||||
|
|
||||||
virtual ~Layer();
|
virtual ~Layer();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否开启消息吞没
|
/// @brief 是否开启消息吞没
|
||||||
bool IsSwallowEventsEnabled() const;
|
bool IsSwallowEventsEnabled() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置消息吞没功能
|
/// @brief 设置消息吞没功能
|
||||||
/// @param enabled 是否启用
|
/// @param enabled 是否启用
|
||||||
void SetSwallowEvents(bool enabled);
|
void SetSwallowEvents(bool enabled);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置裁剪区域
|
/// @brief 设置裁剪区域
|
||||||
/// @param clip_rect 裁剪矩形
|
/// @param clip_rect 裁剪矩形
|
||||||
void SetClipRect(Rect const& clip_rect);
|
void SetClipRect(Rect const& clip_rect);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置图层透明度
|
/// @brief 设置图层透明度
|
||||||
/// @param opacity 透明度
|
/// @param opacity 透明度
|
||||||
void SetOpacity(float opacity) override;
|
void SetOpacity(float opacity) override;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置几何蒙层
|
/// @brief 设置几何蒙层
|
||||||
/// @param mask 蒙层的几何形状
|
/// @param mask 蒙层的几何形状
|
||||||
void SetMaskGeometry(Geometry const& mask);
|
void SetMaskGeometry(Geometry const& mask);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置几何蒙层的二维变换
|
/// @brief 设置几何蒙层的二维变换
|
||||||
/// @param transform 应用于蒙层的二维变换
|
/// @param transform 应用于蒙层的二维变换
|
||||||
void SetMaskTransform(Matrix3x2 const& transform);
|
void SetMaskTransform(Matrix3x2 const& transform);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置图层区域
|
/// @brief 设置图层区域
|
||||||
/// @param area 图层区域属性
|
/// @param area 图层区域属性
|
||||||
void SetArea(LayerArea const& area);
|
void SetArea(LayerArea const& area);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取图层区域
|
/// @brief 获取图层区域
|
||||||
LayerArea const& GetArea() const;
|
LayerArea const& GetArea() const;
|
||||||
|
|
||||||
void Dispatch(Event& evt) override;
|
bool DispatchEvent(Event* evt) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Render(RenderTarget* rt) override;
|
void Render(RenderContext& ctx) override;
|
||||||
|
|
||||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
bool CheckVisibility(RenderContext& ctx) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool swallow_;
|
bool swallow_;
|
||||||
LayerArea area_;
|
LayerArea area_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline bool Layer::IsSwallowEventsEnabled() const { return swallow_; }
|
|
||||||
|
|
||||||
inline void Layer::SetSwallowEvents(bool enabled) { swallow_ = enabled; }
|
|
||||||
|
|
||||||
inline void Layer::SetArea(LayerArea const& area) { area_ = area; }
|
|
||||||
|
|
||||||
inline LayerArea const& Layer::GetArea() const { return area_; }
|
|
||||||
|
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,291 +20,252 @@
|
||||||
|
|
||||||
#include <kiwano/2d/ShapeActor.h>
|
#include <kiwano/2d/ShapeActor.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
ShapeActor::ShapeActor()
|
ShapeActor::ShapeActor()
|
||||||
: stroke_width_(1.f)
|
: stroke_width_(1.f)
|
||||||
, stroke_style_(StrokeStyle::Miter)
|
, stroke_style_()
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
ShapeActor::~ShapeActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect ShapeActor::GetBounds() const
|
|
||||||
{
|
|
||||||
return bounds_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect ShapeActor::GetBoundingBox() const
|
|
||||||
{
|
|
||||||
if (!geo_.IsValid())
|
|
||||||
return Rect{};
|
|
||||||
|
|
||||||
return geo_.GetBoundingBox(GetTransformMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShapeActor::ContainsPoint(const Point& point) const
|
|
||||||
{
|
|
||||||
return geo_.ContainsPoint(point, &GetTransformMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShapeActor::SetStrokeWidth(float width)
|
|
||||||
{
|
|
||||||
stroke_width_ = std::max(width, 0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShapeActor::SetStrokeStyle(StrokeStyle stroke_style)
|
|
||||||
{
|
|
||||||
stroke_style_ = stroke_style;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShapeActor::SetGeometry(Geometry const& geometry)
|
|
||||||
{
|
|
||||||
geo_ = geometry;
|
|
||||||
if (geo_.IsValid())
|
|
||||||
{
|
|
||||||
bounds_ = geo_.GetBoundingBox();
|
|
||||||
SetSize(bounds_.GetSize());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bounds_ = Rect{};
|
|
||||||
SetSize(0.f, 0.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShapeActor::OnRender(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
// Create default brush
|
|
||||||
if (!fill_brush_)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// LineActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
LineActor::LineActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LineActor::~LineActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void LineActor::SetLine(Point const& begin, Point const& end)
|
|
||||||
{
|
|
||||||
if (begin_ != begin || end_ != end)
|
|
||||||
{
|
|
||||||
begin_ = begin;
|
|
||||||
end_ = end;
|
|
||||||
SetGeometry(Geometry::CreateLine(begin, end));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// RectActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
RectActor::RectActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RectActor::~RectActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void RectActor::SetRectSize(Size const& size)
|
|
||||||
{
|
|
||||||
if (size != rect_size_)
|
|
||||||
{
|
|
||||||
rect_size_ = size;
|
|
||||||
SetGeometry(Geometry::CreateRect(Rect{ Point{}, size }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// RoundRectActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
RoundRectActor::RoundRectActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RoundRectActor::~RoundRectActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoundRectActor::SetRadius(Vec2 const& radius)
|
|
||||||
{
|
|
||||||
SetRoundedRect(GetSize(), radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoundRectActor::SetRectSize(Size const& size)
|
|
||||||
{
|
|
||||||
SetRoundedRect(size, radius_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoundRectActor::SetRoundedRect(Size const& size, Vec2 const& radius)
|
|
||||||
{
|
|
||||||
if (rect_size_ != size || radius_ != radius)
|
|
||||||
{
|
|
||||||
rect_size_ = size;
|
|
||||||
radius_ = radius;
|
|
||||||
SetGeometry(Geometry::CreateRoundedRect(Rect{ Point{}, size }, radius));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// CircleActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
CircleActor::CircleActor()
|
|
||||||
: radius_(0.f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CircleActor::~CircleActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CircleActor::SetRadius(float radius)
|
|
||||||
{
|
|
||||||
if (radius_ != radius)
|
|
||||||
{
|
|
||||||
radius_ = radius;
|
|
||||||
SetGeometry(Geometry::CreateCircle(Point{ radius, radius }, radius));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// EllipseActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
EllipseActor::EllipseActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
EllipseActor::~EllipseActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void EllipseActor::SetRadius(Vec2 const& radius)
|
|
||||||
{
|
|
||||||
if (radius_ != radius)
|
|
||||||
{
|
|
||||||
radius_ = radius;
|
|
||||||
SetGeometry(Geometry::CreateEllipse(radius, radius));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// PolygonActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
PolygonActor::PolygonActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PolygonActor::~PolygonActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PolygonActor::SetVertices(Vector<Point> const& points)
|
|
||||||
{
|
|
||||||
if (points.size() > 1)
|
|
||||||
{
|
|
||||||
SetGeometry(
|
|
||||||
GeometrySink()
|
|
||||||
.BeginPath(points[0])
|
|
||||||
.AddLines(&points[1], points.size() - 1)
|
|
||||||
.EndPath(true)
|
|
||||||
.GetGeometry()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// PathShapeActor
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
PathShapeActor::PathShapeActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PathShapeActor::~PathShapeActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PathShapeActor::BeginPath(Point const& begin_pos)
|
|
||||||
{
|
|
||||||
sink_.BeginPath(begin_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PathShapeActor::EndPath(bool closed)
|
|
||||||
{
|
|
||||||
sink_.EndPath(closed);
|
|
||||||
Geometry geo = sink_.GetGeometry();
|
|
||||||
|
|
||||||
if (geo.IsValid())
|
|
||||||
{
|
|
||||||
SetGeometry(geo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PathShapeActor::AddLine(Point const& point)
|
|
||||||
{
|
|
||||||
sink_.AddLine(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PathShapeActor::AddLines(Vector<Point> const& points)
|
|
||||||
{
|
|
||||||
sink_.AddLines(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PathShapeActor::AddBezier(Point const& point1, Point const& point2, Point const& point3)
|
|
||||||
{
|
|
||||||
sink_.AddBezier(point1, point2, point3);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 PathShapeActor::ClearPath()
|
|
||||||
{
|
|
||||||
SetGeometry(Geometry());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShapeActor::~ShapeActor() {}
|
||||||
|
|
||||||
|
Rect ShapeActor::GetBounds() const
|
||||||
|
{
|
||||||
|
return bounds_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect ShapeActor::GetBoundingBox() const
|
||||||
|
{
|
||||||
|
if (!geo_.IsValid())
|
||||||
|
return Rect{};
|
||||||
|
|
||||||
|
return geo_.GetBoundingBox(GetTransformMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeActor::ContainsPoint(const Point& point) const
|
||||||
|
{
|
||||||
|
return geo_.ContainsPoint(point, &GetTransformMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeActor::SetStrokeWidth(float width)
|
||||||
|
{
|
||||||
|
stroke_width_ = std::max(width, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeActor::SetStrokeStyle(const StrokeStyle& stroke_style)
|
||||||
|
{
|
||||||
|
stroke_style_ = stroke_style;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeActor::SetGeometry(Geometry const& geometry)
|
||||||
|
{
|
||||||
|
geo_ = geometry;
|
||||||
|
if (geo_.IsValid())
|
||||||
|
{
|
||||||
|
bounds_ = geo_.GetBoundingBox();
|
||||||
|
SetSize(bounds_.GetSize());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bounds_ = Rect{};
|
||||||
|
SetSize(0.f, 0.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeActor::OnRender(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
// Create default brush
|
||||||
|
if (!fill_brush_)
|
||||||
|
{
|
||||||
|
fill_brush_ = new Brush;
|
||||||
|
fill_brush_->SetColor(Color::White);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stroke_brush_)
|
||||||
|
{
|
||||||
|
stroke_brush_ = new Brush;
|
||||||
|
stroke_brush_->SetColor(Color::Transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetCurrentBrush(stroke_brush_);
|
||||||
|
ctx.DrawGeometry(geo_, stroke_width_ * 2 /* twice width for widening */, stroke_style_);
|
||||||
|
|
||||||
|
ctx.SetCurrentBrush(fill_brush_);
|
||||||
|
ctx.FillGeometry(geo_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeActor::CheckVisibility(RenderContext& ctx) const
|
||||||
|
{
|
||||||
|
return geo_.IsValid() && Actor::CheckVisibility(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// LineActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
LineActor::LineActor() {}
|
||||||
|
|
||||||
|
LineActor::~LineActor() {}
|
||||||
|
|
||||||
|
void LineActor::SetLine(Point const& begin, Point const& end)
|
||||||
|
{
|
||||||
|
if (begin_ != begin || end_ != end)
|
||||||
|
{
|
||||||
|
begin_ = begin;
|
||||||
|
end_ = end;
|
||||||
|
SetGeometry(Geometry::CreateLine(begin, end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// RectActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
RectActor::RectActor() {}
|
||||||
|
|
||||||
|
RectActor::~RectActor() {}
|
||||||
|
|
||||||
|
void RectActor::SetRectSize(Size const& size)
|
||||||
|
{
|
||||||
|
if (size != rect_size_)
|
||||||
|
{
|
||||||
|
rect_size_ = size;
|
||||||
|
SetGeometry(Geometry::CreateRect(Rect{ Point{}, size }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// RoundRectActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
RoundRectActor::RoundRectActor() {}
|
||||||
|
|
||||||
|
RoundRectActor::~RoundRectActor() {}
|
||||||
|
|
||||||
|
void RoundRectActor::SetRadius(Vec2 const& radius)
|
||||||
|
{
|
||||||
|
SetRoundedRect(GetSize(), radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundRectActor::SetRectSize(Size const& size)
|
||||||
|
{
|
||||||
|
SetRoundedRect(size, radius_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundRectActor::SetRoundedRect(Size const& size, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
if (rect_size_ != size || radius_ != radius)
|
||||||
|
{
|
||||||
|
rect_size_ = size;
|
||||||
|
radius_ = radius;
|
||||||
|
SetGeometry(Geometry::CreateRoundedRect(Rect{ Point{}, size }, radius));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// CircleActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
CircleActor::CircleActor()
|
||||||
|
: radius_(0.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CircleActor::~CircleActor() {}
|
||||||
|
|
||||||
|
void CircleActor::SetRadius(float radius)
|
||||||
|
{
|
||||||
|
if (radius_ != radius)
|
||||||
|
{
|
||||||
|
radius_ = radius;
|
||||||
|
SetGeometry(Geometry::CreateCircle(Point{ radius, radius }, radius));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// EllipseActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
EllipseActor::EllipseActor() {}
|
||||||
|
|
||||||
|
EllipseActor::~EllipseActor() {}
|
||||||
|
|
||||||
|
void EllipseActor::SetRadius(Vec2 const& radius)
|
||||||
|
{
|
||||||
|
if (radius_ != radius)
|
||||||
|
{
|
||||||
|
radius_ = radius;
|
||||||
|
SetGeometry(Geometry::CreateEllipse(radius, radius));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// PolygonActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
PolygonActor::PolygonActor() {}
|
||||||
|
|
||||||
|
PolygonActor::~PolygonActor() {}
|
||||||
|
|
||||||
|
void PolygonActor::SetVertices(Vector<Point> const& points)
|
||||||
|
{
|
||||||
|
if (points.size() > 1)
|
||||||
|
{
|
||||||
|
SetGeometry(
|
||||||
|
GeometrySink().BeginPath(points[0]).AddLines(&points[1], points.size() - 1).EndPath(true).GetGeometry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// PathShapeActor
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
PathShapeActor::PathShapeActor() {}
|
||||||
|
|
||||||
|
PathShapeActor::~PathShapeActor() {}
|
||||||
|
|
||||||
|
void PathShapeActor::BeginPath(Point const& begin_pos)
|
||||||
|
{
|
||||||
|
sink_.BeginPath(begin_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathShapeActor::EndPath(bool closed)
|
||||||
|
{
|
||||||
|
sink_.EndPath(closed);
|
||||||
|
Geometry geo = sink_.GetGeometry();
|
||||||
|
|
||||||
|
if (geo.IsValid())
|
||||||
|
{
|
||||||
|
SetGeometry(geo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathShapeActor::AddLine(Point const& point)
|
||||||
|
{
|
||||||
|
sink_.AddLine(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathShapeActor::AddLines(Vector<Point> const& points)
|
||||||
|
{
|
||||||
|
sink_.AddLines(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathShapeActor::AddBezier(Point const& point1, Point const& point2, Point const& point3)
|
||||||
|
{
|
||||||
|
sink_.AddBezier(point1, point2, point3);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 PathShapeActor::ClearPath()
|
||||||
|
{
|
||||||
|
SetGeometry(Geometry());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,383 +20,415 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/renderer/Brush.h>
|
#include <kiwano/render/Brush.h>
|
||||||
#include <kiwano/renderer/Geometry.h>
|
#include <kiwano/render/Geometry.h>
|
||||||
#include <kiwano/renderer/GeometrySink.h>
|
#include <kiwano/render/GeometrySink.h>
|
||||||
#include <kiwano/renderer/StrokeStyle.h>
|
#include <kiwano/render/StrokeStyle.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(ShapeActor);
|
KGE_DECLARE_SMART_PTR(ShapeActor);
|
||||||
KGE_DECLARE_SMART_PTR(LineActor);
|
KGE_DECLARE_SMART_PTR(LineActor);
|
||||||
KGE_DECLARE_SMART_PTR(RectActor);
|
KGE_DECLARE_SMART_PTR(RectActor);
|
||||||
KGE_DECLARE_SMART_PTR(RoundRectActor);
|
KGE_DECLARE_SMART_PTR(RoundRectActor);
|
||||||
KGE_DECLARE_SMART_PTR(CircleActor);
|
KGE_DECLARE_SMART_PTR(CircleActor);
|
||||||
KGE_DECLARE_SMART_PTR(EllipseActor);
|
KGE_DECLARE_SMART_PTR(EllipseActor);
|
||||||
KGE_DECLARE_SMART_PTR(PolygonActor);
|
KGE_DECLARE_SMART_PTR(PolygonActor);
|
||||||
KGE_DECLARE_SMART_PTR(PathShapeActor);
|
KGE_DECLARE_SMART_PTR(PathShapeActor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 二维形状角色
|
* @brief 二维形状角色
|
||||||
*/
|
*/
|
||||||
class KGE_API ShapeActor
|
class KGE_API ShapeActor : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 构造二维形状角色
|
||||||
/// @brief 构造二维形状角色
|
ShapeActor();
|
||||||
ShapeActor();
|
|
||||||
|
virtual ~ShapeActor();
|
||||||
virtual ~ShapeActor();
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取填充画刷
|
||||||
/// @brief 获取填充画刷
|
BrushPtr GetFillBrush() const;
|
||||||
BrushPtr GetFillBrush() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取轮廓画刷
|
||||||
/// @brief 获取轮廓画刷
|
BrushPtr GetStrokeBrush() const;
|
||||||
BrushPtr GetStrokeBrush() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取线条宽度
|
||||||
/// @brief 获取线条宽度
|
float GetStrokeWidth() const;
|
||||||
float GetStrokeWidth() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取线条样式
|
||||||
/// @brief 获取线条样式
|
const StrokeStyle& GetStrokeStyle() const;
|
||||||
StrokeStyle SetStrokeStyle() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取形状
|
||||||
/// @brief 获取形状
|
Geometry GetGeometry() const;
|
||||||
Geometry GetGeometry() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取边界
|
||||||
/// @brief 获取边界
|
Rect GetBounds() const override;
|
||||||
Rect GetBounds() const override;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 获取外切包围盒
|
||||||
/// @brief 获取外切包围盒
|
Rect GetBoundingBox() const override;
|
||||||
Rect GetBoundingBox() const override;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 判断点是否在形状内
|
||||||
/// @brief 判断点是否在形状内
|
bool ContainsPoint(const Point& point) const override;
|
||||||
bool ContainsPoint(const Point& point) const override;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置填充颜色
|
||||||
/// @brief 设置填充颜色
|
/// @param color 填充颜色
|
||||||
/// @param color 填充颜色
|
void SetFillColor(Color const& color);
|
||||||
void SetFillColor(Color const& color);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置填充画刷
|
||||||
/// @brief 设置填充画刷
|
/// @param[in] brush 填充画刷
|
||||||
/// @param[in] brush 填充画刷
|
void SetFillBrush(BrushPtr brush);
|
||||||
void SetFillBrush(BrushPtr brush);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置轮廓颜色
|
||||||
/// @brief 设置轮廓颜色
|
/// @param color 轮廓颜色
|
||||||
/// @param color 轮廓颜色
|
void SetStrokeColor(Color const& color);
|
||||||
void SetStrokeColor(Color const& color);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置轮廓画刷
|
||||||
/// @brief 设置轮廓画刷
|
/// @param[in] brush 轮廓画刷
|
||||||
/// @param[in] brush 轮廓画刷
|
void SetStrokeBrush(BrushPtr brush);
|
||||||
void SetStrokeBrush(BrushPtr brush);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置线条宽度,默认为 1.0
|
||||||
/// @brief 设置线条宽度,默认为 1.0
|
void SetStrokeWidth(float width);
|
||||||
void SetStrokeWidth(float width);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置线条样式
|
||||||
/// @brief 设置线条样式
|
void SetStrokeStyle(const StrokeStyle& stroke_style);
|
||||||
void SetStrokeStyle(StrokeStyle stroke_style);
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置几何形状
|
||||||
/// @brief 设置几何形状
|
void SetGeometry(Geometry const& geometry);
|
||||||
void SetGeometry(Geometry const& geometry);
|
|
||||||
|
void OnRender(RenderContext& ctx) override;
|
||||||
void OnRender(RenderTarget* rt) override;
|
|
||||||
|
protected:
|
||||||
protected:
|
bool CheckVisibility(RenderContext& ctx) const override;
|
||||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
|
||||||
|
private:
|
||||||
private:
|
BrushPtr fill_brush_;
|
||||||
BrushPtr fill_brush_;
|
BrushPtr stroke_brush_;
|
||||||
BrushPtr stroke_brush_;
|
float stroke_width_;
|
||||||
float stroke_width_;
|
StrokeStyle stroke_style_;
|
||||||
StrokeStyle stroke_style_;
|
Rect bounds_;
|
||||||
Rect bounds_;
|
Geometry geo_;
|
||||||
Geometry geo_;
|
};
|
||||||
};
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 线段图形角色
|
||||||
/// \~chinese
|
class KGE_API LineActor : public ShapeActor
|
||||||
/// @brief 线段图形角色
|
{
|
||||||
class KGE_API LineActor
|
public:
|
||||||
: public ShapeActor
|
LineActor();
|
||||||
{
|
|
||||||
public:
|
virtual ~LineActor();
|
||||||
LineActor();
|
|
||||||
|
/// \~chinese
|
||||||
virtual ~LineActor();
|
/// @brief 获取线段起点
|
||||||
|
Point const& GetBeginPoint() const;
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取线段起点
|
/// \~chinese
|
||||||
Point const& GetBeginPoint() const;
|
/// @brief 获取线段终点
|
||||||
|
Point const& GetEndPoint() const;
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取线段终点
|
/// \~chinese
|
||||||
Point const& GetEndPoint() const;
|
/// @brief 设置线段起点
|
||||||
|
/// @param begin 线段起点
|
||||||
/// \~chinese
|
void SetBeginPoint(Point const& begin);
|
||||||
/// @brief 设置线段起点
|
|
||||||
/// @param begin 线段起点
|
/// \~chinese
|
||||||
void SetBeginPoint(Point const& begin);
|
/// @brief 设置线段终点
|
||||||
|
/// @param end 线段终点
|
||||||
/// \~chinese
|
void SetEndPoint(Point const& end);
|
||||||
/// @brief 设置线段终点
|
|
||||||
/// @param end 线段终点
|
/// \~chinese
|
||||||
void SetEndPoint(Point const& end);
|
/// @brief 设置矩形大小
|
||||||
|
/// @param begin 线段起点
|
||||||
/// \~chinese
|
/// @param end 线段终点
|
||||||
/// @brief 设置矩形大小
|
void SetLine(Point const& begin, Point const& end);
|
||||||
/// @param begin 线段起点
|
|
||||||
/// @param end 线段终点
|
private:
|
||||||
void SetLine(Point const& begin, Point const& end);
|
Point begin_;
|
||||||
|
Point end_;
|
||||||
private:
|
};
|
||||||
Point begin_;
|
|
||||||
Point end_;
|
/// \~chinese
|
||||||
};
|
/// @brief 矩形角色
|
||||||
|
class KGE_API RectActor : public ShapeActor
|
||||||
|
{
|
||||||
/// \~chinese
|
public:
|
||||||
/// @brief 矩形角色
|
RectActor();
|
||||||
class KGE_API RectActor
|
|
||||||
: public ShapeActor
|
virtual ~RectActor();
|
||||||
{
|
|
||||||
public:
|
/// \~chinese
|
||||||
RectActor();
|
/// @brief 获取矩形大小
|
||||||
|
Size const& GetRectSize() const;
|
||||||
virtual ~RectActor();
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 设置矩形大小
|
||||||
/// @brief 获取矩形大小
|
/// @param size 矩形大小
|
||||||
Size const& GetRectSize() const;
|
void SetRectSize(Size const& size);
|
||||||
|
|
||||||
/// \~chinese
|
private:
|
||||||
/// @brief 设置矩形大小
|
Size rect_size_;
|
||||||
/// @param size 矩形大小
|
};
|
||||||
void SetRectSize(Size const& size);
|
|
||||||
|
/// \~chinese
|
||||||
private:
|
/// @brief 圆角矩形角色
|
||||||
Size rect_size_;
|
class KGE_API RoundRectActor : public ShapeActor
|
||||||
};
|
{
|
||||||
|
public:
|
||||||
|
RoundRectActor();
|
||||||
|
|
||||||
/// \~chinese
|
virtual ~RoundRectActor();
|
||||||
/// @brief 圆角矩形角色
|
|
||||||
class KGE_API RoundRectActor
|
/// \~chinese
|
||||||
: public ShapeActor
|
/// @brief 获取圆角半径
|
||||||
{
|
Vec2 GetRadius() const;
|
||||||
public:
|
|
||||||
RoundRectActor();
|
/// \~chinese
|
||||||
|
/// @brief 获取圆角矩形大小
|
||||||
virtual ~RoundRectActor();
|
Size GetRectSize() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取圆角半径
|
/// @brief 设置圆角半径
|
||||||
Vec2 GetRadius() const;
|
/// @param radius 圆角半径
|
||||||
|
void SetRadius(Vec2 const& radius);
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取圆角矩形大小
|
/// \~chinese
|
||||||
Size GetRectSize() const;
|
/// @brief 设置圆角矩形大小
|
||||||
|
/// @param size 圆角矩形大小
|
||||||
/// \~chinese
|
void SetRectSize(Size const& size);
|
||||||
/// @brief 设置圆角半径
|
|
||||||
/// @param radius 圆角半径
|
/// \~chinese
|
||||||
void SetRadius(Vec2 const& radius);
|
/// @brief 设置圆角矩形
|
||||||
|
/// @param size 圆角矩形大小
|
||||||
/// \~chinese
|
/// @param radius 圆角半径
|
||||||
/// @brief 设置圆角矩形大小
|
void SetRoundedRect(Size const& size, Vec2 const& radius);
|
||||||
/// @param size 圆角矩形大小
|
|
||||||
void SetRectSize(Size const& size);
|
private:
|
||||||
|
Size rect_size_;
|
||||||
/// \~chinese
|
Vec2 radius_;
|
||||||
/// @brief 设置圆角矩形
|
};
|
||||||
/// @param size 圆角矩形大小
|
|
||||||
/// @param radius 圆角半径
|
/// \~chinese
|
||||||
void SetRoundedRect(Size const& size, Vec2 const& radius);
|
/// @brief 圆形角色
|
||||||
|
class KGE_API CircleActor : public ShapeActor
|
||||||
private:
|
{
|
||||||
Size rect_size_;
|
public:
|
||||||
Vec2 radius_;
|
CircleActor();
|
||||||
};
|
|
||||||
|
virtual ~CircleActor();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 圆形角色
|
/// @brief 获取圆形半径
|
||||||
class KGE_API CircleActor
|
float GetRadius() const;
|
||||||
: public ShapeActor
|
|
||||||
{
|
/// \~chinese
|
||||||
public:
|
/// @brief 设置圆形半径
|
||||||
CircleActor();
|
/// @param radius 圆形半径
|
||||||
|
void SetRadius(float radius);
|
||||||
virtual ~CircleActor();
|
|
||||||
|
private:
|
||||||
/// \~chinese
|
float radius_;
|
||||||
/// @brief 获取圆形半径
|
};
|
||||||
float GetRadius() const;
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 椭圆角色
|
||||||
/// @brief 设置圆形半径
|
class KGE_API EllipseActor : public ShapeActor
|
||||||
/// @param radius 圆形半径
|
{
|
||||||
void SetRadius(float radius);
|
public:
|
||||||
|
EllipseActor();
|
||||||
private:
|
|
||||||
float radius_;
|
virtual ~EllipseActor();
|
||||||
};
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取椭圆半径
|
||||||
/// \~chinese
|
Vec2 GetRadius() const;
|
||||||
/// @brief 椭圆角色
|
|
||||||
class KGE_API EllipseActor
|
/// \~chinese
|
||||||
: public ShapeActor
|
/// @brief 设置椭圆半径
|
||||||
{
|
/// @param radius 椭圆半径
|
||||||
public:
|
void SetRadius(Vec2 const& radius);
|
||||||
EllipseActor();
|
|
||||||
|
private:
|
||||||
virtual ~EllipseActor();
|
Vec2 radius_;
|
||||||
|
};
|
||||||
/// \~chinese
|
|
||||||
/// @brief 获取椭圆半径
|
/// \~chinese
|
||||||
Vec2 GetRadius() const;
|
/// @brief 多边形角色
|
||||||
|
class KGE_API PolygonActor : public ShapeActor
|
||||||
/// \~chinese
|
{
|
||||||
/// @brief 设置椭圆半径
|
public:
|
||||||
/// @param radius 椭圆半径
|
PolygonActor();
|
||||||
void SetRadius(Vec2 const& radius);
|
|
||||||
|
virtual ~PolygonActor();
|
||||||
private:
|
|
||||||
Vec2 radius_;
|
/// \~chinese
|
||||||
};
|
/// @brief 设置多边形端点
|
||||||
|
/// @param points 多边形端点集合
|
||||||
|
void SetVertices(Vector<Point> const& points);
|
||||||
/// \~chinese
|
};
|
||||||
/// @brief 多边形角色
|
|
||||||
class KGE_API PolygonActor
|
/// \~chinese
|
||||||
: public ShapeActor
|
/// @brief 路径图形角色
|
||||||
{
|
class KGE_API PathShapeActor : public ShapeActor
|
||||||
public:
|
{
|
||||||
PolygonActor();
|
public:
|
||||||
|
PathShapeActor();
|
||||||
virtual ~PolygonActor();
|
|
||||||
|
virtual ~PathShapeActor();
|
||||||
/// \~chinese
|
|
||||||
/// @brief 设置多边形端点
|
/// \~chinese
|
||||||
/// @param points 多边形端点集合
|
/// @brief 开始添加路径
|
||||||
void SetVertices(Vector<Point> const& points);
|
/// @param begin_pos 起始点
|
||||||
};
|
void BeginPath(Point const& begin_pos = Point());
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 结束添加路径
|
||||||
/// @brief 路径图形角色
|
/// @param closed 路径是否闭合
|
||||||
class KGE_API PathShapeActor
|
void EndPath(bool closed = true);
|
||||||
: public ShapeActor
|
|
||||||
{
|
/// \~chinese
|
||||||
public:
|
/// @brief 添加一条线段
|
||||||
PathShapeActor();
|
/// @param point 线段端点
|
||||||
|
void AddLine(Point const& point);
|
||||||
virtual ~PathShapeActor();
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 添加多条线段
|
||||||
/// @brief 开始添加路径
|
/// @param points 线段端点集合
|
||||||
/// @param begin_pos 起始点
|
void AddLines(Vector<Point> const& points);
|
||||||
void BeginPath(Point const& begin_pos = Point());
|
|
||||||
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 添加一条三次方贝塞尔曲线
|
||||||
/// @brief 结束添加路径
|
/// @param point1 贝塞尔曲线的第一个控制点
|
||||||
/// @param closed 路径是否闭合
|
/// @param point2 贝塞尔曲线的第二个控制点
|
||||||
void EndPath(bool closed = true);
|
/// @param point3 贝塞尔曲线的终点
|
||||||
|
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
|
||||||
/// \~chinese
|
|
||||||
/// @brief 添加一条线段
|
/// \~chinese
|
||||||
/// @param point 线段端点
|
/// @brief 添加弧线
|
||||||
void AddLine(Point const& point);
|
/// @param point 椭圆圆心
|
||||||
|
/// @param radius 椭圆半径
|
||||||
/// \~chinese
|
/// @param rotation 椭圆旋转角度
|
||||||
/// @brief 添加多条线段
|
/// @param clockwise 顺时针 or 逆时针
|
||||||
/// @param points 线段端点集合
|
/// @param is_small 是否取小于 180° 的弧
|
||||||
void AddLines(Vector<Point> const& points);
|
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加一条三次方贝塞尔曲线
|
/// @brief 清除路径
|
||||||
/// @param point1 贝塞尔曲线的第一个控制点
|
void ClearPath();
|
||||||
/// @param point2 贝塞尔曲线的第二个控制点
|
|
||||||
/// @param point3 贝塞尔曲线的终点
|
private:
|
||||||
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
|
GeometrySink sink_;
|
||||||
|
};
|
||||||
/// \~chinese
|
|
||||||
/// @brief 添加弧线
|
/** @} */
|
||||||
/// @param point 椭圆圆心
|
|
||||||
/// @param radius 椭圆半径
|
inline void ShapeActor::SetStrokeColor(Color const& color)
|
||||||
/// @param rotation 椭圆旋转角度
|
{
|
||||||
/// @param clockwise 顺时针 or 逆时针
|
if (!stroke_brush_)
|
||||||
/// @param is_small 是否取小于 180° 的弧
|
{
|
||||||
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
|
stroke_brush_ = new Brush;
|
||||||
|
}
|
||||||
/// \~chinese
|
stroke_brush_->SetColor(color);
|
||||||
/// @brief 清除路径
|
|
||||||
void ClearPath();
|
|
||||||
|
|
||||||
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_; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 const StrokeStyle& ShapeActor::GetStrokeStyle() 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_;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,68 +19,64 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/Sprite.h>
|
#include <kiwano/2d/Sprite.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Sprite::Sprite()
|
Sprite::Sprite() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Sprite::~Sprite()
|
Sprite::~Sprite() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sprite::Load(String const& file_path)
|
bool Sprite::Load(String const& file_path)
|
||||||
{
|
{
|
||||||
FramePtr frame = new (std::nothrow) Frame;
|
FramePtr frame = new (std::nothrow) Frame;
|
||||||
if (frame->Load(file_path))
|
if (frame->Load(file_path))
|
||||||
{
|
{
|
||||||
SetFrame(frame);
|
SetFrame(frame);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
bool Sprite::Load(Resource const& res)
|
|
||||||
{
|
|
||||||
FramePtr frame = new (std::nothrow) Frame;
|
|
||||||
if (frame->Load(res))
|
|
||||||
{
|
|
||||||
SetFrame(frame);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sprite::SetCropRect(const Rect& crop_rect)
|
|
||||||
{
|
|
||||||
if (frame_)
|
|
||||||
{
|
|
||||||
frame_->SetCropRect(crop_rect);
|
|
||||||
SetSize(Size{ frame_->GetWidth(), frame_->GetHeight() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sprite::SetFrame(FramePtr frame)
|
|
||||||
{
|
|
||||||
if (frame_ != frame)
|
|
||||||
{
|
|
||||||
frame_ = frame;
|
|
||||||
if (frame_)
|
|
||||||
{
|
|
||||||
SetSize(Size{ frame_->GetWidth(), frame_->GetHeight() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sprite::OnRender(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
rt->DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sprite::CheckVisibilty(RenderTarget* rt) const
|
|
||||||
{
|
|
||||||
return frame_ && frame_->IsValid() && Actor::CheckVisibilty(rt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sprite::Load(Resource const& res)
|
||||||
|
{
|
||||||
|
FramePtr frame = new (std::nothrow) Frame;
|
||||||
|
if (frame->Load(res))
|
||||||
|
{
|
||||||
|
SetFrame(frame);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::SetCropRect(const Rect& crop_rect)
|
||||||
|
{
|
||||||
|
if (frame_)
|
||||||
|
{
|
||||||
|
frame_->SetCropRect(crop_rect);
|
||||||
|
SetSize(Size{ frame_->GetWidth(), frame_->GetHeight() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::SetFrame(FramePtr frame)
|
||||||
|
{
|
||||||
|
if (frame_ != frame)
|
||||||
|
{
|
||||||
|
frame_ = frame;
|
||||||
|
if (frame_)
|
||||||
|
{
|
||||||
|
SetSize(Size{ frame_->GetWidth(), frame_->GetHeight() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::OnRender(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
ctx.DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sprite::CheckVisibility(RenderContext& ctx) const
|
||||||
|
{
|
||||||
|
return frame_ && frame_->IsValid() && Actor::CheckVisibility(ctx);
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -24,60 +24,61 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(Sprite);
|
KGE_DECLARE_SMART_PTR(Sprite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 精灵
|
* @brief 精灵
|
||||||
*/
|
*/
|
||||||
class KGE_API Sprite
|
class KGE_API Sprite : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
Sprite();
|
||||||
Sprite();
|
|
||||||
|
|
||||||
virtual ~Sprite();
|
virtual ~Sprite();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载本地图片
|
/// @brief 加载本地图片
|
||||||
/// @param file_path 本地图片路径
|
/// @param file_path 本地图片路径
|
||||||
bool Load(String const& file_path);
|
bool Load(String const& file_path);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 加载图像资源
|
/// @brief 加载图像资源
|
||||||
/// @param res 图片资源
|
/// @param res 图片资源
|
||||||
bool Load(Resource const& res);
|
bool Load(Resource const& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 使用矩形区域裁剪精灵
|
/// @brief 使用矩形区域裁剪精灵
|
||||||
/// @param crop_rect 裁剪矩形
|
/// @param crop_rect 裁剪矩形
|
||||||
void SetCropRect(const Rect& crop_rect);
|
void SetCropRect(const Rect& crop_rect);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取帧图像
|
/// @brief 获取帧图像
|
||||||
FramePtr GetFrame() const;
|
FramePtr GetFrame() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置图像帧
|
/// @brief 设置图像帧
|
||||||
/// @param[in] frame 图像帧
|
/// @param[in] frame 图像帧
|
||||||
void SetFrame(FramePtr frame);
|
void SetFrame(FramePtr frame);
|
||||||
|
|
||||||
void OnRender(RenderTarget* rt) override;
|
void OnRender(RenderContext& ctx) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
bool CheckVisibility(RenderContext& ctx) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FramePtr frame_;
|
FramePtr frame_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline FramePtr Sprite::GetFrame() const { return frame_; }
|
|
||||||
|
|
||||||
|
inline FramePtr Sprite::GetFrame() const
|
||||||
|
{
|
||||||
|
return frame_;
|
||||||
}
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,49 +20,47 @@
|
||||||
|
|
||||||
#include <kiwano/2d/Stage.h>
|
#include <kiwano/2d/Stage.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Stage::Stage()
|
Stage::Stage()
|
||||||
{
|
{
|
||||||
SetStage(this);
|
SetStage(this);
|
||||||
|
|
||||||
SetAnchor(Vec2{ 0, 0 });
|
|
||||||
SetSize(Renderer::instance().GetOutputSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
Stage::~Stage()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stage::OnEnter()
|
|
||||||
{
|
|
||||||
KGE_SYS_LOG(L"Stage entered");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stage::OnExit()
|
|
||||||
{
|
|
||||||
KGE_SYS_LOG(L"Stage exited");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stage::RenderBorder(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
rt->SetBrushOpacity(1.0f);
|
|
||||||
|
|
||||||
if (!border_fill_brush_)
|
|
||||||
{
|
|
||||||
border_fill_brush_ = new Brush;
|
|
||||||
border_fill_brush_->SetColor(Color(Color::Red, .4f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!border_stroke_brush_)
|
|
||||||
{
|
|
||||||
border_stroke_brush_ = new Brush;
|
|
||||||
border_stroke_brush_->SetColor(Color(Color::Red, .8f));
|
|
||||||
}
|
|
||||||
|
|
||||||
Actor::RenderBorder(rt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
SetAnchor(Vec2{ 0, 0 });
|
||||||
|
SetSize(Renderer::Instance().GetOutputSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stage::~Stage() {}
|
||||||
|
|
||||||
|
void Stage::OnEnter()
|
||||||
|
{
|
||||||
|
KGE_SYS_LOG(L"Stage entered");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stage::OnExit()
|
||||||
|
{
|
||||||
|
KGE_SYS_LOG(L"Stage exited");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stage::RenderBorder(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
ctx.SetBrushOpacity(GetDisplayedOpacity());
|
||||||
|
|
||||||
|
if (!border_fill_brush_)
|
||||||
|
{
|
||||||
|
border_fill_brush_ = new Brush;
|
||||||
|
border_fill_brush_->SetColor(Color(Color::Red, .4f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!border_stroke_brush_)
|
||||||
|
{
|
||||||
|
border_stroke_brush_ = new Brush;
|
||||||
|
border_stroke_brush_->SetColor(Color(Color::Red, .8f));
|
||||||
|
}
|
||||||
|
|
||||||
|
Actor::RenderBorder(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,90 +20,88 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/renderer/Brush.h>
|
#include <kiwano/render/Brush.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(Stage);
|
KGE_DECLARE_SMART_PTR(Stage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 舞台
|
* @brief 舞台
|
||||||
* @details 舞台是所有角色的载体,是导演直接控制的对象
|
* @details 舞台是所有角色的载体,是导演直接控制的对象
|
||||||
* @see kiwano::Actor kiwano::Director
|
* @see kiwano::Actor kiwano::Director
|
||||||
*/
|
*/
|
||||||
class KGE_API Stage
|
class KGE_API Stage : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
friend class Transition;
|
||||||
friend class Transition;
|
friend class Director;
|
||||||
friend class Director;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Stage();
|
Stage();
|
||||||
|
|
||||||
virtual ~Stage();
|
virtual ~Stage();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 进入舞台时
|
/// @brief 进入舞台时
|
||||||
/// @details 重载该函数以处理进入舞台前的行为
|
/// @details 重载该函数以处理进入舞台前的行为
|
||||||
virtual void OnEnter();
|
virtual void OnEnter();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 退出舞台时
|
/// @brief 退出舞台时
|
||||||
/// @details 重载该函数以处理退出舞台前的行为
|
/// @details 重载该函数以处理退出舞台前的行为
|
||||||
virtual void OnExit();
|
virtual void OnExit();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取角色边界填充画刷
|
/// @brief 获取角色边界填充画刷
|
||||||
BrushPtr GetBorderFillBrush() const;
|
BrushPtr GetBorderFillBrush() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取角色边界轮廓画刷
|
/// @brief 获取角色边界轮廓画刷
|
||||||
BrushPtr GetBorderStrokeBrush() const;
|
BrushPtr GetBorderStrokeBrush() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置角色边界填充画刷
|
/// @brief 设置角色边界填充画刷
|
||||||
void SetBorderFillBrush(BrushPtr brush);
|
void SetBorderFillBrush(BrushPtr brush);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置角色边界轮廓画刷
|
/// @brief 设置角色边界轮廓画刷
|
||||||
void SetBorderStrokeBrush(BrushPtr brush);
|
void SetBorderStrokeBrush(BrushPtr brush);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 绘制所有子角色的边界
|
/// @brief 绘制所有子角色的边界
|
||||||
void RenderBorder(RenderTarget* rt) override;
|
void RenderBorder(RenderContext& ctx) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BrushPtr border_fill_brush_;
|
BrushPtr border_fill_brush_;
|
||||||
BrushPtr border_stroke_brush_;
|
BrushPtr border_stroke_brush_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline BrushPtr Stage::GetBorderFillBrush() const
|
|
||||||
{
|
|
||||||
return border_fill_brush_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline BrushPtr Stage::GetBorderStrokeBrush() const
|
|
||||||
{
|
|
||||||
return border_stroke_brush_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Stage::SetBorderFillBrush(BrushPtr brush)
|
|
||||||
{
|
|
||||||
border_fill_brush_ = brush;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Stage::SetBorderStrokeBrush(BrushPtr brush)
|
|
||||||
{
|
|
||||||
border_stroke_brush_ = brush;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
inline BrushPtr Stage::GetBorderFillBrush() const
|
||||||
|
{
|
||||||
|
return border_fill_brush_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline BrushPtr Stage::GetBorderStrokeBrush() const
|
||||||
|
{
|
||||||
|
return border_stroke_brush_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Stage::SetBorderFillBrush(BrushPtr brush)
|
||||||
|
{
|
||||||
|
border_fill_brush_ = brush;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Stage::SetBorderStrokeBrush(BrushPtr brush)
|
||||||
|
{
|
||||||
|
border_stroke_brush_ = brush;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,110 +20,113 @@
|
||||||
|
|
||||||
#include <kiwano/2d/TextActor.h>
|
#include <kiwano/2d/TextActor.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
TextStyle text_default_style;
|
TextStyle text_default_style;
|
||||||
|
|
||||||
void InitDefaultTextStyle()
|
void InitDefaultTextStyle()
|
||||||
{
|
{
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
if (!inited)
|
if (!inited)
|
||||||
{
|
{
|
||||||
inited = true;
|
inited = true;
|
||||||
|
|
||||||
// 默认使用白色画刷填充文字
|
// 默认使用白色画刷填充文字
|
||||||
text_default_style.fill_brush = new Brush;
|
text_default_style.fill_brush = new Brush;
|
||||||
text_default_style.fill_brush->SetColor(Color::White);
|
text_default_style.fill_brush->SetColor(Color::White);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextActor::SetDefaultStyle(TextStyle const & style)
|
|
||||||
{
|
|
||||||
text_default_style = style;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TextStyle& TextActor::GetDefaultStyle()
|
|
||||||
{
|
|
||||||
return text_default_style;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextActor::TextActor()
|
|
||||||
: TextActor(String())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TextActor::TextActor(String const& text)
|
|
||||||
: TextActor(text, text_default_style)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TextActor::TextActor(String const& text, const TextStyle& style)
|
|
||||||
: show_underline_(false)
|
|
||||||
, show_strikethrough_(false)
|
|
||||||
{
|
|
||||||
InitDefaultTextStyle();
|
|
||||||
|
|
||||||
SetText(text);
|
|
||||||
SetStyle(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextActor::~TextActor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextActor::OnRender(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
rt->DrawTextLayout(text_layout_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextActor::OnUpdate(Duration dt)
|
|
||||||
{
|
|
||||||
UpdateLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextActor::UpdateLayout()
|
|
||||||
{
|
|
||||||
if (text_layout_.IsDirty())
|
|
||||||
{
|
|
||||||
text_layout_.Update();
|
|
||||||
|
|
||||||
if (show_underline_)
|
|
||||||
text_layout_.SetUnderline(true, 0, text_layout_.GetText().length());
|
|
||||||
|
|
||||||
if (show_strikethrough_)
|
|
||||||
text_layout_.SetStrikethrough(true, 0, text_layout_.GetText().length());
|
|
||||||
|
|
||||||
SetSize(text_layout_.GetLayoutSize());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextActor::CheckVisibilty(RenderTarget* rt) const
|
|
||||||
{
|
|
||||||
return text_layout_.IsValid() && Actor::CheckVisibilty(rt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextActor::SetFillColor(Color const& color)
|
|
||||||
{
|
|
||||||
if (!text_layout_.GetFillBrush())
|
|
||||||
{
|
|
||||||
BrushPtr brush = new Brush;
|
|
||||||
text_layout_.SetFillBrush(brush);
|
|
||||||
}
|
|
||||||
text_layout_.GetFillBrush()->SetColor(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextActor::SetOutlineColor(Color const& outline_color)
|
|
||||||
{
|
|
||||||
if (!text_layout_.GetOutlineBrush())
|
|
||||||
{
|
|
||||||
BrushPtr brush = new Brush;
|
|
||||||
text_layout_.SetOutlineBrush(brush);
|
|
||||||
}
|
|
||||||
text_layout_.GetOutlineBrush()->SetColor(outline_color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void TextActor::SetDefaultStyle(TextStyle const& style)
|
||||||
|
{
|
||||||
|
text_default_style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextStyle& TextActor::GetDefaultStyle()
|
||||||
|
{
|
||||||
|
InitDefaultTextStyle();
|
||||||
|
return text_default_style;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextActor::TextActor()
|
||||||
|
: TextActor(String())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextActor::TextActor(String const& text)
|
||||||
|
: TextActor(text, GetDefaultStyle())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextActor::TextActor(String const& text, const TextStyle& style)
|
||||||
|
: show_underline_(false)
|
||||||
|
, show_strikethrough_(false)
|
||||||
|
{
|
||||||
|
SetText(text);
|
||||||
|
SetStyle(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextActor::~TextActor() {}
|
||||||
|
|
||||||
|
void TextActor::OnRender(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
ctx.DrawTextLayout(text_layout_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextActor::OnUpdate(Duration dt)
|
||||||
|
{
|
||||||
|
UpdateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextActor::UpdateLayout()
|
||||||
|
{
|
||||||
|
if (text_layout_.IsDirty())
|
||||||
|
{
|
||||||
|
text_layout_.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text_layout_.GetDirtyFlag() & TextLayout::DirtyFlag::Updated)
|
||||||
|
{
|
||||||
|
text_layout_.SetDirtyFlag(TextLayout::DirtyFlag::Clean);
|
||||||
|
|
||||||
|
if (show_underline_)
|
||||||
|
text_layout_.SetUnderline(true, 0, text_layout_.GetText().length());
|
||||||
|
|
||||||
|
if (show_strikethrough_)
|
||||||
|
text_layout_.SetStrikethrough(true, 0, text_layout_.GetText().length());
|
||||||
|
|
||||||
|
SetSize(text_layout_.GetLayoutSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextActor::CheckVisibility(RenderContext& ctx) const
|
||||||
|
{
|
||||||
|
return text_layout_.IsValid() && Actor::CheckVisibility(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextActor::SetFillColor(Color const& color)
|
||||||
|
{
|
||||||
|
if (!text_layout_.GetFillBrush() || text_layout_.GetFillBrush() == GetDefaultStyle().fill_brush)
|
||||||
|
{
|
||||||
|
BrushPtr brush = new Brush;
|
||||||
|
text_layout_.SetFillBrush(brush);
|
||||||
|
}
|
||||||
|
text_layout_.GetFillBrush()->SetColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextActor::SetOutlineColor(Color const& outline_color)
|
||||||
|
{
|
||||||
|
if (!text_layout_.GetOutlineBrush() || text_layout_.GetOutlineBrush() == GetDefaultStyle().outline_brush)
|
||||||
|
{
|
||||||
|
BrushPtr brush = new Brush;
|
||||||
|
text_layout_.SetOutlineBrush(brush);
|
||||||
|
}
|
||||||
|
text_layout_.GetOutlineBrush()->SetColor(outline_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,275 +20,282 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/renderer/Color.h>
|
#include <kiwano/render/Color.h>
|
||||||
#include <kiwano/renderer/TextLayout.h>
|
#include <kiwano/render/TextLayout.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(TextActor);
|
KGE_DECLARE_SMART_PTR(TextActor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actors
|
* \addtogroup Actors
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 文本角色
|
* @brief 文本角色
|
||||||
*/
|
*/
|
||||||
class KGE_API TextActor
|
class KGE_API TextActor : public Actor
|
||||||
: public Actor
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 构建空的文本角色
|
||||||
/// @brief 构建空的文本角色
|
TextActor();
|
||||||
TextActor();
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构建文本角色
|
/// @brief 构建文本角色
|
||||||
/// @param text 文字内容
|
/// @param text 文字内容
|
||||||
explicit TextActor(const String& text);
|
explicit TextActor(const String& text);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构建文本角色
|
/// @brief 构建文本角色
|
||||||
/// @param text 文字内容
|
/// @param text 文字内容
|
||||||
/// @param style 文本样式
|
/// @param style 文本样式
|
||||||
TextActor(const String& text, const TextStyle& style);
|
TextActor(const String& text, const TextStyle& style);
|
||||||
|
|
||||||
virtual ~TextActor();
|
virtual ~TextActor();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取文本
|
/// @brief 获取文本
|
||||||
const String& GetText() const;
|
const String& GetText() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取文本样式
|
/// @brief 获取文本样式
|
||||||
const TextStyle& GetStyle() const;
|
const TextStyle& GetStyle() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取文本布局
|
/// @brief 获取文本布局
|
||||||
const TextLayout& GetLayout() const;
|
const TextLayout& GetLayout() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取填充画刷
|
/// @brief 获取文本布局大小
|
||||||
BrushPtr GetFillBrush() const;
|
Size GetLayoutSize() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取描边画刷
|
/// @brief 获取填充画刷
|
||||||
BrushPtr GetOutlineBrush() const;
|
BrushPtr GetFillBrush() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取字体
|
/// @brief 获取描边画刷
|
||||||
FontPtr GetFont() const;
|
BrushPtr GetOutlineBrush() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文本
|
/// @brief 获取字体
|
||||||
void SetText(String const& text);
|
FontPtr GetFont() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文本样式
|
/// @brief 设置文本
|
||||||
void SetStyle(const TextStyle& style);
|
void SetText(String const& text);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置字体
|
/// @brief 设置文本样式
|
||||||
void SetFont(FontPtr font);
|
void SetStyle(const TextStyle& style);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置字体族
|
/// @brief 设置字体
|
||||||
void SetFontFamily(String const& family);
|
void SetFont(FontPtr font);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置字号(默认值为 18)
|
/// @brief 设置字体族
|
||||||
void SetFontSize(float size);
|
void SetFontFamily(String const& family);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置字体粗细值(默认值为 FontWeight::Normal)
|
/// @brief 设置字号(默认值为 18)
|
||||||
void SetFontWeight(uint32_t weight);
|
void SetFontSize(float size);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字填充画刷
|
/// @brief 设置字体粗细值(默认值为 FontWeight::Normal)
|
||||||
void SetFillBrush(BrushPtr brush);
|
void SetFontWeight(uint32_t weight);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字填充颜色(默认值为 Color::White)
|
/// @brief 设置文字填充画刷
|
||||||
void SetFillColor(Color const& color);
|
void SetFillBrush(BrushPtr brush);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字斜体(默认值为 false)
|
/// @brief 设置文字填充颜色(默认值为 Color::White)
|
||||||
void SetItalic(bool italic);
|
void SetFillColor(Color const& color);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文本自动换行的宽度(默认为 0)
|
/// @brief 设置文字斜体(默认值为 false)
|
||||||
void SetWrapWidth(float wrap_width);
|
void SetItalic(bool italic);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置行间距(默认为 0)
|
/// @brief 设置文本自动换行的宽度(默认为 0)
|
||||||
void SetLineSpacing(float line_spacing);
|
void SetWrapWidth(float wrap_width);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置对齐方式(默认为 TextAlign::Left)
|
/// @brief 设置行间距(默认为 0)
|
||||||
void SetAlignment(TextAlign align);
|
void SetLineSpacing(float line_spacing);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字描边画刷
|
/// @brief 设置对齐方式(默认为 TextAlign::Left)
|
||||||
void SetOutlineBrush(BrushPtr brush);
|
void SetAlignment(TextAlign align);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字描边颜色
|
/// @brief 设置文字描边画刷
|
||||||
void SetOutlineColor(Color const& outline_color);
|
void SetOutlineBrush(BrushPtr brush);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字描边线宽
|
/// @brief 设置文字描边颜色
|
||||||
void SetOutlineWidth(float outline_width);
|
void SetOutlineColor(Color const& outline_color);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置文字描边线相交样式
|
/// @brief 设置文字描边线宽
|
||||||
void SetOutlineStroke(StrokeStyle outline_stroke);
|
void SetOutlineWidth(float outline_width);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置是否显示下划线(默认值为 false)
|
/// @brief 设置文字描边线相交样式
|
||||||
void SetUnderline(bool enable);
|
void SetOutlineStroke(const StrokeStyle& outline_stroke);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置是否显示删除线(默认值为 false)
|
/// @brief 设置是否显示下划线(默认值为 false)
|
||||||
void SetStrikethrough(bool enable);
|
void SetUnderline(bool enable);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 更新文字布局
|
/// @brief 设置是否显示删除线(默认值为 false)
|
||||||
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
|
void SetStrikethrough(bool enable);
|
||||||
void UpdateLayout();
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置默认文字样式
|
/// @brief 更新文字布局
|
||||||
static void SetDefaultStyle(TextStyle const& style);
|
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
|
||||||
|
void UpdateLayout();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取默认文字样式
|
/// @brief 设置默认文字样式
|
||||||
static const TextStyle& GetDefaultStyle();
|
static void SetDefaultStyle(TextStyle const& style);
|
||||||
|
|
||||||
void OnRender(RenderTarget* rt) override;
|
/// \~chinese
|
||||||
|
/// @brief 获取默认文字样式
|
||||||
|
static const TextStyle& GetDefaultStyle();
|
||||||
|
|
||||||
void OnUpdate(Duration dt) override;
|
void OnRender(RenderContext& ctx) override;
|
||||||
|
|
||||||
protected:
|
void OnUpdate(Duration dt) override;
|
||||||
bool CheckVisibilty(RenderTarget* rt) const override;
|
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
bool show_underline_;
|
bool CheckVisibility(RenderContext& ctx) const override;
|
||||||
bool show_strikethrough_;
|
|
||||||
TextLayout text_layout_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
private:
|
||||||
|
bool show_underline_;
|
||||||
|
bool show_strikethrough_;
|
||||||
|
TextLayout text_layout_;
|
||||||
|
};
|
||||||
|
|
||||||
inline const String& TextActor::GetText() const
|
/** @} */
|
||||||
{
|
|
||||||
return text_layout_.GetText();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FontPtr TextActor::GetFont() const
|
|
||||||
{
|
|
||||||
return text_layout_.GetStyle().font;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const TextStyle& TextActor::GetStyle() const
|
|
||||||
{
|
|
||||||
return text_layout_.GetStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const TextLayout& TextActor::GetLayout() const
|
|
||||||
{
|
|
||||||
return text_layout_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline BrushPtr TextActor::GetFillBrush() const
|
|
||||||
{
|
|
||||||
return text_layout_.GetFillBrush();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline BrushPtr TextActor::GetOutlineBrush() const
|
|
||||||
{
|
|
||||||
return text_layout_.GetOutlineBrush();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetText(String const& text)
|
|
||||||
{
|
|
||||||
text_layout_.SetText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetStyle(const TextStyle& style)
|
|
||||||
{
|
|
||||||
text_layout_.SetStyle(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetFont(FontPtr font)
|
|
||||||
{
|
|
||||||
text_layout_.SetFont(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetFontFamily(String const& family)
|
|
||||||
{
|
|
||||||
text_layout_.SetFontFamily(family);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetFontSize(float size)
|
|
||||||
{
|
|
||||||
text_layout_.SetFontSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetFontWeight(uint32_t weight)
|
|
||||||
{
|
|
||||||
text_layout_.SetFontWeight(weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetItalic(bool italic)
|
|
||||||
{
|
|
||||||
text_layout_.SetItalic(italic);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetWrapWidth(float wrap_width)
|
|
||||||
{
|
|
||||||
text_layout_.SetWrapWidth(wrap_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetLineSpacing(float line_spacing)
|
|
||||||
{
|
|
||||||
text_layout_.SetLineSpacing(line_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetAlignment(TextAlign align)
|
|
||||||
{
|
|
||||||
text_layout_.SetAlignment(align);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetUnderline(bool enable)
|
|
||||||
{
|
|
||||||
show_underline_ = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetStrikethrough(bool enable)
|
|
||||||
{
|
|
||||||
show_strikethrough_ = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetFillBrush(BrushPtr brush)
|
|
||||||
{
|
|
||||||
text_layout_.SetFillBrush(brush);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetOutlineBrush(BrushPtr brush)
|
|
||||||
{
|
|
||||||
text_layout_.SetOutlineBrush(brush);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetOutlineWidth(float outline_width)
|
|
||||||
{
|
|
||||||
text_layout_.SetOutlineWidth(outline_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TextActor::SetOutlineStroke(StrokeStyle outline_stroke)
|
|
||||||
{
|
|
||||||
text_layout_.SetOutlineStroke(outline_stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
inline const String& TextActor::GetText() const
|
||||||
|
{
|
||||||
|
return text_layout_.GetText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline FontPtr TextActor::GetFont() const
|
||||||
|
{
|
||||||
|
return text_layout_.GetStyle().font;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const TextStyle& TextActor::GetStyle() const
|
||||||
|
{
|
||||||
|
return text_layout_.GetStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const TextLayout& TextActor::GetLayout() const
|
||||||
|
{
|
||||||
|
return text_layout_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Size TextActor::GetLayoutSize() const
|
||||||
|
{
|
||||||
|
return text_layout_.GetLayoutSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline BrushPtr TextActor::GetFillBrush() const
|
||||||
|
{
|
||||||
|
return text_layout_.GetFillBrush();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline BrushPtr TextActor::GetOutlineBrush() const
|
||||||
|
{
|
||||||
|
return text_layout_.GetOutlineBrush();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetText(String const& text)
|
||||||
|
{
|
||||||
|
text_layout_.SetText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetStyle(const TextStyle& style)
|
||||||
|
{
|
||||||
|
text_layout_.SetStyle(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetFont(FontPtr font)
|
||||||
|
{
|
||||||
|
text_layout_.SetFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetFontFamily(String const& family)
|
||||||
|
{
|
||||||
|
text_layout_.SetFontFamily(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetFontSize(float size)
|
||||||
|
{
|
||||||
|
text_layout_.SetFontSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetFontWeight(uint32_t weight)
|
||||||
|
{
|
||||||
|
text_layout_.SetFontWeight(weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetItalic(bool italic)
|
||||||
|
{
|
||||||
|
text_layout_.SetItalic(italic);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetWrapWidth(float wrap_width)
|
||||||
|
{
|
||||||
|
text_layout_.SetWrapWidth(wrap_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetLineSpacing(float line_spacing)
|
||||||
|
{
|
||||||
|
text_layout_.SetLineSpacing(line_spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetAlignment(TextAlign align)
|
||||||
|
{
|
||||||
|
text_layout_.SetAlignment(align);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetUnderline(bool enable)
|
||||||
|
{
|
||||||
|
show_underline_ = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetStrikethrough(bool enable)
|
||||||
|
{
|
||||||
|
show_strikethrough_ = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetFillBrush(BrushPtr brush)
|
||||||
|
{
|
||||||
|
text_layout_.SetFillBrush(brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetOutlineBrush(BrushPtr brush)
|
||||||
|
{
|
||||||
|
text_layout_.SetOutlineBrush(brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetOutlineWidth(float outline_width)
|
||||||
|
{
|
||||||
|
text_layout_.SetOutlineWidth(outline_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TextActor::SetOutlineStroke(const StrokeStyle& outline_stroke)
|
||||||
|
{
|
||||||
|
text_layout_.SetOutlineStroke(outline_stroke);
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -22,28 +22,25 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Transform::Transform()
|
Transform::Transform()
|
||||||
: position()
|
: position()
|
||||||
, rotation(0.f)
|
, rotation(0.f)
|
||||||
, scale(1.f, 1.f)
|
, scale(1.f, 1.f)
|
||||||
, skew(0.f, 0.f)
|
, skew(0.f, 0.f)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Matrix3x2 Transform::ToMatrix() const
|
|
||||||
{
|
|
||||||
if (!skew.IsOrigin())
|
|
||||||
{
|
|
||||||
return Matrix3x2::Skewing(skew) * Matrix3x2::SRT(position, scale, rotation);
|
|
||||||
}
|
|
||||||
return Matrix3x2::SRT(position, scale, rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Transform::operator== (Transform const& rhs) const
|
|
||||||
{
|
|
||||||
return position == rhs.position &&
|
|
||||||
rotation == rhs.rotation &&
|
|
||||||
scale == rhs.scale &&
|
|
||||||
skew == rhs.skew;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix3x2 Transform::ToMatrix() const
|
||||||
|
{
|
||||||
|
if (!skew.IsOrigin())
|
||||||
|
{
|
||||||
|
return Matrix3x2::Skewing(skew) * Matrix3x2::SRT(position, scale, rotation);
|
||||||
|
}
|
||||||
|
return Matrix3x2::SRT(position, scale, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Transform::operator==(Transform const& rhs) const
|
||||||
|
{
|
||||||
|
return position == rhs.position && rotation == rhs.rotation && scale == rhs.scale && skew == rhs.skew;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,25 +23,25 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 二维放射变换
|
* @brief 二维放射变换
|
||||||
*/
|
*/
|
||||||
class Transform
|
class Transform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
float rotation; ///< 旋转
|
float rotation; ///< 旋转
|
||||||
Point position; ///< 坐标
|
Point position; ///< 坐标
|
||||||
Point scale; ///< 缩放
|
Point scale; ///< 缩放
|
||||||
Point skew; ///< 错切角度
|
Point skew; ///< 错切角度
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Transform();
|
Transform();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 将二维放射变换转换为矩阵
|
/// @brief 将二维放射变换转换为矩阵
|
||||||
Matrix3x2 ToMatrix() const;
|
Matrix3x2 ToMatrix() const;
|
||||||
|
|
||||||
bool operator== (const Transform& rhs) const;
|
bool operator==(const Transform& rhs) const;
|
||||||
};
|
};
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,369 +18,355 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/Transition.h>
|
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
#include <kiwano/2d/Stage.h>
|
#include <kiwano/2d/Stage.h>
|
||||||
#include <kiwano/platform/Window.h>
|
#include <kiwano/2d/Transition.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
#include <kiwano/renderer/Renderer.h>
|
#include <kiwano/platform/Window.h>
|
||||||
|
#include <kiwano/render/Renderer.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
// Transition
|
// Transition
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
|
|
||||||
Transition::Transition(Duration duration)
|
Transition::Transition(Duration duration)
|
||||||
: done_(false)
|
: done_(false)
|
||||||
, duration_(duration)
|
, duration_(duration)
|
||||||
, delta_()
|
, delta_()
|
||||||
, process_(0)
|
, process_(0)
|
||||||
, window_size_()
|
, window_size_()
|
||||||
, out_stage_(nullptr)
|
, out_stage_(nullptr)
|
||||||
, in_stage_(nullptr)
|
, in_stage_(nullptr)
|
||||||
, out_layer_()
|
, out_layer_()
|
||||||
, in_layer_()
|
, in_layer_()
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Transition::~Transition()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Transition::IsDone()
|
|
||||||
{
|
|
||||||
return done_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transition::Init(StagePtr prev, StagePtr next)
|
|
||||||
{
|
|
||||||
process_ = 0;
|
|
||||||
delta_ = Duration{};
|
|
||||||
|
|
||||||
out_stage_ = prev;
|
|
||||||
in_stage_ = next;
|
|
||||||
window_size_ = Renderer::instance().GetOutputSize();
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
in_layer_.SetAreaRect(Rect{ Point(), window_size_ });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
out_layer_.SetAreaRect(Rect{ Point(), window_size_ });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transition::Update(Duration dt)
|
|
||||||
{
|
|
||||||
if (duration_.IsZero())
|
|
||||||
{
|
|
||||||
process_ = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delta_ += dt;
|
|
||||||
process_ = std::min(delta_ / duration_, 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process_ >= 1)
|
|
||||||
{
|
|
||||||
this->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transition::Render(RenderTarget* rt)
|
|
||||||
{
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
out_stage_->PrepareToRender(rt);
|
|
||||||
rt->PushClipRect(Rect{ Point{}, window_size_ });
|
|
||||||
rt->PushLayer(out_layer_);
|
|
||||||
|
|
||||||
out_stage_->Render(rt);
|
|
||||||
|
|
||||||
rt->PopLayer();
|
|
||||||
rt->PopClipRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
in_stage_->PrepareToRender(rt);
|
|
||||||
rt->PushClipRect(Rect{ Point{}, window_size_ });
|
|
||||||
rt->PushLayer(in_layer_);
|
|
||||||
|
|
||||||
in_stage_->Render(rt);
|
|
||||||
|
|
||||||
rt->PopLayer();
|
|
||||||
rt->PopClipRect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transition::Stop()
|
|
||||||
{
|
|
||||||
done_ = true;
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// BoxTransition
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
BoxTransition::BoxTransition(Duration duration)
|
|
||||||
: Transition(duration)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void BoxTransition::Init(StagePtr prev, StagePtr next)
|
|
||||||
{
|
|
||||||
Transition::Init(prev, next);
|
|
||||||
|
|
||||||
in_layer_.SetOpacity(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BoxTransition::Update(Duration dt)
|
|
||||||
{
|
|
||||||
Transition::Update(dt);
|
|
||||||
|
|
||||||
if (process_ < .5f)
|
|
||||||
{
|
|
||||||
out_layer_.SetAreaRect(
|
|
||||||
Rect(
|
|
||||||
window_size_.x * process_,
|
|
||||||
window_size_.y * process_,
|
|
||||||
window_size_.x * (1 - process_),
|
|
||||||
window_size_.y * (1 - process_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out_layer_.SetOpacity(0.f);
|
|
||||||
in_layer_.SetOpacity(1.f);
|
|
||||||
in_layer_.SetAreaRect(
|
|
||||||
Rect(
|
|
||||||
window_size_.x * (1 - process_),
|
|
||||||
window_size_.y * (1 - process_),
|
|
||||||
window_size_.x * process_,
|
|
||||||
window_size_.y * process_
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// EmergeTransition
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
EmergeTransition::EmergeTransition(Duration duration)
|
|
||||||
: Transition(duration)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmergeTransition::Init(StagePtr prev, StagePtr next)
|
|
||||||
{
|
|
||||||
Transition::Init(prev, next);
|
|
||||||
|
|
||||||
out_layer_.SetOpacity(1.f);
|
|
||||||
in_layer_.SetOpacity(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmergeTransition::Update(Duration dt)
|
|
||||||
{
|
|
||||||
Transition::Update(dt);
|
|
||||||
|
|
||||||
out_layer_.SetOpacity(1 - process_);
|
|
||||||
in_layer_.SetOpacity(process_);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// FadeTransition
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
FadeTransition::FadeTransition(Duration duration)
|
|
||||||
: Transition(duration)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FadeTransition::Init(StagePtr prev, StagePtr next)
|
|
||||||
{
|
|
||||||
Transition::Init(prev, next);
|
|
||||||
|
|
||||||
out_layer_.SetOpacity(1.f);
|
|
||||||
in_layer_.SetOpacity(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FadeTransition::Update(Duration dt)
|
|
||||||
{
|
|
||||||
Transition::Update(dt);
|
|
||||||
|
|
||||||
if (process_ < 0.5)
|
|
||||||
{
|
|
||||||
out_layer_.SetOpacity(1 - process_ * 2);
|
|
||||||
in_layer_.SetOpacity(0.f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out_layer_.SetOpacity(0.f);
|
|
||||||
in_layer_.SetOpacity((process_ - 0.5f) * 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// MoveTransition
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
MoveTransition::MoveTransition(Duration duration, Type type)
|
|
||||||
: Transition(duration)
|
|
||||||
, type_(type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveTransition::Init(StagePtr prev, StagePtr next)
|
|
||||||
{
|
|
||||||
Transition::Init(prev, next);
|
|
||||||
|
|
||||||
switch (type_)
|
|
||||||
{
|
|
||||||
case Type::Up:
|
|
||||||
pos_delta_ = Point(0, -window_size_.y);
|
|
||||||
start_pos_ = Point(0, window_size_.y);
|
|
||||||
break;
|
|
||||||
case Type::Down:
|
|
||||||
pos_delta_ = Point(0, window_size_.y);
|
|
||||||
start_pos_ = Point(0, -window_size_.y);
|
|
||||||
break;
|
|
||||||
case Type::Left:
|
|
||||||
pos_delta_ = Point(-window_size_.x, 0);
|
|
||||||
start_pos_ = Point(window_size_.x, 0);
|
|
||||||
break;
|
|
||||||
case Type::Right:
|
|
||||||
pos_delta_ = Point(window_size_.x, 0);
|
|
||||||
start_pos_ = Point(-window_size_.x, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
out_stage_->SetTransform(Transform{});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
auto transform = Transform{};
|
|
||||||
transform.position = start_pos_;
|
|
||||||
in_stage_->SetTransform(transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveTransition::Update(Duration dt)
|
|
||||||
{
|
|
||||||
Transition::Update(dt);
|
|
||||||
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
auto transform = Transform{};
|
|
||||||
transform.position = pos_delta_ * process_;
|
|
||||||
out_stage_->SetTransform(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
auto transform = Transform{};
|
|
||||||
transform.position = start_pos_ + pos_delta_ * process_;
|
|
||||||
in_stage_->SetTransform(transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveTransition::Reset()
|
|
||||||
{
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
out_stage_->SetTransform(Transform{});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
in_stage_->SetTransform(Transform{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// RotationTransition
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
RotationTransition::RotationTransition(Duration duration, float rotation)
|
|
||||||
: Transition(duration)
|
|
||||||
, rotation_(rotation)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotationTransition::Init(StagePtr prev, StagePtr next)
|
|
||||||
{
|
|
||||||
Transition::Init(prev, next);
|
|
||||||
|
|
||||||
auto transform = Transform{};
|
|
||||||
transform.position = Point{ window_size_.x / 2, window_size_.y / 2 };
|
|
||||||
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
out_stage_->SetTransform(transform);
|
|
||||||
out_stage_->SetAnchor(Vec2{ 0.5f, 0.5f });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
in_stage_->SetTransform(transform);
|
|
||||||
in_stage_->SetAnchor(Vec2{ 0.5f, 0.5f });
|
|
||||||
}
|
|
||||||
|
|
||||||
in_layer_.SetOpacity(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotationTransition::Update(Duration dt)
|
|
||||||
{
|
|
||||||
Transition::Update(dt);
|
|
||||||
|
|
||||||
if (process_ < .5f)
|
|
||||||
{
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
auto transform = out_stage_->GetTransform();
|
|
||||||
transform.scale = Point{ (.5f - process_) * 2, (.5f - process_) * 2 };
|
|
||||||
transform.rotation = rotation_ * (.5f - process_) * 2;
|
|
||||||
out_stage_->SetTransform(transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
out_layer_.SetOpacity(0.f);
|
|
||||||
in_layer_.SetOpacity(1.f);
|
|
||||||
|
|
||||||
auto transform = in_stage_->GetTransform();
|
|
||||||
transform.scale = Point{ (process_ - .5f) * 2, (process_ - .5f) * 2 };
|
|
||||||
transform.rotation = rotation_ * (process_ - .5f) * 2;
|
|
||||||
|
|
||||||
in_stage_->SetTransform(transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RotationTransition::Reset()
|
|
||||||
{
|
|
||||||
if (out_stage_)
|
|
||||||
{
|
|
||||||
out_stage_->SetTransform(Transform{});
|
|
||||||
out_stage_->SetAnchor(Vec2{ 0.f, 0.f });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_stage_)
|
|
||||||
{
|
|
||||||
in_stage_->SetTransform(Transform{});
|
|
||||||
in_stage_->SetAnchor(Vec2{ 0.f, 0.f });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transition::~Transition() {}
|
||||||
|
|
||||||
|
bool Transition::IsDone()
|
||||||
|
{
|
||||||
|
return done_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transition::Init(StagePtr prev, StagePtr next)
|
||||||
|
{
|
||||||
|
process_ = 0;
|
||||||
|
delta_ = Duration{};
|
||||||
|
|
||||||
|
out_stage_ = prev;
|
||||||
|
in_stage_ = next;
|
||||||
|
window_size_ = Renderer::Instance().GetOutputSize();
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
in_layer_.SetAreaRect(Rect{ Point(), window_size_ });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
out_layer_.SetAreaRect(Rect{ Point(), window_size_ });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transition::Update(Duration dt)
|
||||||
|
{
|
||||||
|
if (duration_.IsZero())
|
||||||
|
{
|
||||||
|
process_ = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delta_ += dt;
|
||||||
|
process_ = std::min(delta_ / duration_, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process_ >= 1)
|
||||||
|
{
|
||||||
|
this->Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transition::Render(RenderContext& ctx)
|
||||||
|
{
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
out_stage_->PrepareToRender(ctx);
|
||||||
|
ctx.PushClipRect(Rect{ Point{}, window_size_ });
|
||||||
|
ctx.PushLayer(out_layer_);
|
||||||
|
|
||||||
|
out_stage_->Render(ctx);
|
||||||
|
|
||||||
|
ctx.PopLayer();
|
||||||
|
ctx.PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
in_stage_->PrepareToRender(ctx);
|
||||||
|
ctx.PushClipRect(Rect{ Point{}, window_size_ });
|
||||||
|
ctx.PushLayer(in_layer_);
|
||||||
|
|
||||||
|
in_stage_->Render(ctx);
|
||||||
|
|
||||||
|
ctx.PopLayer();
|
||||||
|
ctx.PopClipRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transition::Stop()
|
||||||
|
{
|
||||||
|
done_ = true;
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// BoxTransition
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
BoxTransition::BoxTransition(Duration duration)
|
||||||
|
: Transition(duration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxTransition::Init(StagePtr prev, StagePtr next)
|
||||||
|
{
|
||||||
|
Transition::Init(prev, next);
|
||||||
|
|
||||||
|
in_layer_.SetOpacity(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxTransition::Update(Duration dt)
|
||||||
|
{
|
||||||
|
Transition::Update(dt);
|
||||||
|
|
||||||
|
if (process_ < .5f)
|
||||||
|
{
|
||||||
|
out_layer_.SetAreaRect(Rect(window_size_.x * process_, window_size_.y * process_,
|
||||||
|
window_size_.x * (1 - process_), window_size_.y * (1 - process_)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out_layer_.SetOpacity(0.f);
|
||||||
|
in_layer_.SetOpacity(1.f);
|
||||||
|
in_layer_.SetAreaRect(Rect(window_size_.x * (1 - process_), window_size_.y * (1 - process_),
|
||||||
|
window_size_.x * process_, window_size_.y * process_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// EmergeTransition
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
EmergeTransition::EmergeTransition(Duration duration)
|
||||||
|
: Transition(duration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmergeTransition::Init(StagePtr prev, StagePtr next)
|
||||||
|
{
|
||||||
|
Transition::Init(prev, next);
|
||||||
|
|
||||||
|
out_layer_.SetOpacity(1.f);
|
||||||
|
in_layer_.SetOpacity(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmergeTransition::Update(Duration dt)
|
||||||
|
{
|
||||||
|
Transition::Update(dt);
|
||||||
|
|
||||||
|
out_layer_.SetOpacity(1 - process_);
|
||||||
|
in_layer_.SetOpacity(process_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// FadeTransition
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
FadeTransition::FadeTransition(Duration duration)
|
||||||
|
: Transition(duration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeTransition::Init(StagePtr prev, StagePtr next)
|
||||||
|
{
|
||||||
|
Transition::Init(prev, next);
|
||||||
|
|
||||||
|
out_layer_.SetOpacity(1.f);
|
||||||
|
in_layer_.SetOpacity(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FadeTransition::Update(Duration dt)
|
||||||
|
{
|
||||||
|
Transition::Update(dt);
|
||||||
|
|
||||||
|
if (process_ < 0.5)
|
||||||
|
{
|
||||||
|
out_layer_.SetOpacity(1 - process_ * 2);
|
||||||
|
in_layer_.SetOpacity(0.f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out_layer_.SetOpacity(0.f);
|
||||||
|
in_layer_.SetOpacity((process_ - 0.5f) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// MoveTransition
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
MoveTransition::MoveTransition(Duration duration, Type type)
|
||||||
|
: Transition(duration)
|
||||||
|
, type_(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveTransition::Init(StagePtr prev, StagePtr next)
|
||||||
|
{
|
||||||
|
Transition::Init(prev, next);
|
||||||
|
|
||||||
|
switch (type_)
|
||||||
|
{
|
||||||
|
case Type::Up:
|
||||||
|
pos_delta_ = Point(0, -window_size_.y);
|
||||||
|
start_pos_ = Point(0, window_size_.y);
|
||||||
|
break;
|
||||||
|
case Type::Down:
|
||||||
|
pos_delta_ = Point(0, window_size_.y);
|
||||||
|
start_pos_ = Point(0, -window_size_.y);
|
||||||
|
break;
|
||||||
|
case Type::Left:
|
||||||
|
pos_delta_ = Point(-window_size_.x, 0);
|
||||||
|
start_pos_ = Point(window_size_.x, 0);
|
||||||
|
break;
|
||||||
|
case Type::Right:
|
||||||
|
pos_delta_ = Point(window_size_.x, 0);
|
||||||
|
start_pos_ = Point(-window_size_.x, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
out_stage_->SetTransform(Transform{});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
auto transform = Transform{};
|
||||||
|
transform.position = start_pos_;
|
||||||
|
in_stage_->SetTransform(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveTransition::Update(Duration dt)
|
||||||
|
{
|
||||||
|
Transition::Update(dt);
|
||||||
|
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
auto transform = Transform{};
|
||||||
|
transform.position = pos_delta_ * process_;
|
||||||
|
out_stage_->SetTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
auto transform = Transform{};
|
||||||
|
transform.position = start_pos_ + pos_delta_ * process_;
|
||||||
|
in_stage_->SetTransform(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveTransition::Reset()
|
||||||
|
{
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
out_stage_->SetTransform(Transform{});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
in_stage_->SetTransform(Transform{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// RotationTransition
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
RotationTransition::RotationTransition(Duration duration, float rotation)
|
||||||
|
: Transition(duration)
|
||||||
|
, rotation_(rotation)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotationTransition::Init(StagePtr prev, StagePtr next)
|
||||||
|
{
|
||||||
|
Transition::Init(prev, next);
|
||||||
|
|
||||||
|
auto transform = Transform{};
|
||||||
|
transform.position = Point{ window_size_.x / 2, window_size_.y / 2 };
|
||||||
|
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
out_stage_->SetTransform(transform);
|
||||||
|
out_stage_->SetAnchor(Vec2{ 0.5f, 0.5f });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
in_stage_->SetTransform(transform);
|
||||||
|
in_stage_->SetAnchor(Vec2{ 0.5f, 0.5f });
|
||||||
|
}
|
||||||
|
|
||||||
|
in_layer_.SetOpacity(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotationTransition::Update(Duration dt)
|
||||||
|
{
|
||||||
|
Transition::Update(dt);
|
||||||
|
|
||||||
|
if (process_ < .5f)
|
||||||
|
{
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
auto transform = out_stage_->GetTransform();
|
||||||
|
transform.scale = Point{ (.5f - process_) * 2, (.5f - process_) * 2 };
|
||||||
|
transform.rotation = rotation_ * (.5f - process_) * 2;
|
||||||
|
out_stage_->SetTransform(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
out_layer_.SetOpacity(0.f);
|
||||||
|
in_layer_.SetOpacity(1.f);
|
||||||
|
|
||||||
|
auto transform = in_stage_->GetTransform();
|
||||||
|
transform.scale = Point{ (process_ - .5f) * 2, (process_ - .5f) * 2 };
|
||||||
|
transform.rotation = rotation_ * (process_ - .5f) * 2;
|
||||||
|
|
||||||
|
in_stage_->SetTransform(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotationTransition::Reset()
|
||||||
|
{
|
||||||
|
if (out_stage_)
|
||||||
|
{
|
||||||
|
out_stage_->SetTransform(Transform{});
|
||||||
|
out_stage_->SetAnchor(Vec2{ 0.f, 0.f });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_stage_)
|
||||||
|
{
|
||||||
|
in_stage_->SetTransform(Transform{});
|
||||||
|
in_stage_->SetAnchor(Vec2{ 0.f, 0.f });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,262 +20,219 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/Stage.h>
|
#include <kiwano/2d/Stage.h>
|
||||||
#include <kiwano/renderer/LayerArea.h>
|
#include <kiwano/render/LayerArea.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
class Director;
|
class Director;
|
||||||
class RenderTarget;
|
class RenderContext;
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(Transition);
|
KGE_DECLARE_SMART_PTR(Transition);
|
||||||
KGE_DECLARE_SMART_PTR(FadeTransition);
|
KGE_DECLARE_SMART_PTR(FadeTransition);
|
||||||
KGE_DECLARE_SMART_PTR(EmergeTransition);
|
KGE_DECLARE_SMART_PTR(EmergeTransition);
|
||||||
KGE_DECLARE_SMART_PTR(BoxTransition);
|
KGE_DECLARE_SMART_PTR(BoxTransition);
|
||||||
KGE_DECLARE_SMART_PTR(MoveTransition);
|
KGE_DECLARE_SMART_PTR(MoveTransition);
|
||||||
KGE_DECLARE_SMART_PTR(RotationTransition);
|
KGE_DECLARE_SMART_PTR(RotationTransition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 舞台过渡动画
|
* @brief 舞台过渡动画
|
||||||
*/
|
*/
|
||||||
class KGE_API Transition
|
class KGE_API Transition : public virtual ObjectBase
|
||||||
: public ObjectBase
|
{
|
||||||
{
|
friend class Director;
|
||||||
friend class Director;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 构建空的场景过渡动画
|
* @brief 构建空的场景过渡动画
|
||||||
* @param duration 动画时长
|
* @param duration 动画时长
|
||||||
*/
|
*/
|
||||||
explicit Transition(
|
explicit Transition(Duration duration);
|
||||||
Duration duration
|
|
||||||
);
|
|
||||||
|
|
||||||
virtual ~Transition();
|
virtual ~Transition();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 场景过渡动画是否已结束
|
* @brief 场景过渡动画是否已结束
|
||||||
*/
|
*/
|
||||||
bool IsDone();
|
bool IsDone();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 初始化场景过渡动画
|
* @brief 初始化场景过渡动画
|
||||||
* @param[in] prev 转出场景
|
* @param[in] prev 转出场景
|
||||||
* @param[in] next 转入场景
|
* @param[in] next 转入场景
|
||||||
*/
|
*/
|
||||||
virtual void Init(
|
virtual void Init(StagePtr prev, StagePtr next);
|
||||||
StagePtr prev,
|
|
||||||
StagePtr next
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 更新过渡动画
|
* @brief 更新过渡动画
|
||||||
* @param dt 距上一次更新的时间间隔
|
* @param dt 距上一次更新的时间间隔
|
||||||
*/
|
*/
|
||||||
virtual void Update(Duration dt);
|
virtual void Update(Duration dt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 渲染过度动画
|
* @brief 渲染过度动画
|
||||||
* @param[in] rt 渲染目标
|
* @param[in] ctx 渲染上下文
|
||||||
*/
|
*/
|
||||||
virtual void Render(RenderTarget* rt);
|
virtual void Render(RenderContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 停止动画
|
* @brief 停止动画
|
||||||
*/
|
*/
|
||||||
virtual void Stop();
|
virtual void Stop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 重置动画
|
* @brief 重置动画
|
||||||
*/
|
*/
|
||||||
virtual void Reset() {}
|
virtual void Reset() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool done_;
|
bool done_;
|
||||||
float process_;
|
float process_;
|
||||||
Duration duration_;
|
Duration duration_;
|
||||||
Duration delta_;
|
Duration delta_;
|
||||||
Size window_size_;
|
Size window_size_;
|
||||||
StagePtr out_stage_;
|
StagePtr out_stage_;
|
||||||
StagePtr in_stage_;
|
StagePtr in_stage_;
|
||||||
LayerArea out_layer_;
|
LayerArea out_layer_;
|
||||||
LayerArea in_layer_;
|
LayerArea in_layer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 淡入淡出过渡动画
|
||||||
|
* @details 前一场景淡出动画结束后,后一场景淡入
|
||||||
|
*/
|
||||||
|
class FadeTransition : public Transition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 构建淡入淡出过渡动画
|
||||||
|
* @param duration 动画时长
|
||||||
|
*/
|
||||||
|
explicit FadeTransition(Duration duration);
|
||||||
|
|
||||||
/**
|
protected:
|
||||||
* \~chinese
|
void Update(Duration dt) override;
|
||||||
* @brief 淡入淡出过渡动画
|
|
||||||
* @details 前一场景淡出动画结束后,后一场景淡入
|
|
||||||
*/
|
|
||||||
class FadeTransition
|
|
||||||
: public Transition
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 构建淡入淡出过渡动画
|
|
||||||
* @param duration 动画时长
|
|
||||||
*/
|
|
||||||
explicit FadeTransition(
|
|
||||||
Duration duration
|
|
||||||
);
|
|
||||||
|
|
||||||
protected:
|
virtual void Init(StagePtr prev, StagePtr next) override;
|
||||||
void Update(Duration dt) override;
|
};
|
||||||
|
|
||||||
virtual void Init(
|
/**
|
||||||
StagePtr prev,
|
* \~chinese
|
||||||
StagePtr next
|
* @brief 渐变过渡动画
|
||||||
) override;
|
* @details 前一场景淡出动画的同时,后一场景淡入
|
||||||
};
|
*/
|
||||||
|
class EmergeTransition : public Transition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 构建渐变过渡动画
|
||||||
|
* @param duration 动画时长
|
||||||
|
*/
|
||||||
|
explicit EmergeTransition(Duration duration);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Update(Duration dt) override;
|
||||||
|
|
||||||
/**
|
virtual void Init(StagePtr prev, StagePtr next) override;
|
||||||
* \~chinese
|
};
|
||||||
* @brief 渐变过渡动画
|
|
||||||
* @details 前一场景淡出动画的同时,后一场景淡入
|
|
||||||
*/
|
|
||||||
class EmergeTransition
|
|
||||||
: public Transition
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 构建渐变过渡动画
|
|
||||||
* @param duration 动画时长
|
|
||||||
*/
|
|
||||||
explicit EmergeTransition(
|
|
||||||
Duration duration
|
|
||||||
);
|
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
void Update(Duration dt) override;
|
* \~chinese
|
||||||
|
* @brief 盒状过渡动画
|
||||||
|
* @details 前一场景以盒状收缩至消失,后一场景以盒状扩大
|
||||||
|
*/
|
||||||
|
class BoxTransition : public Transition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 构建盒状过渡动画
|
||||||
|
* @param duration 动画时长
|
||||||
|
*/
|
||||||
|
explicit BoxTransition(Duration duration);
|
||||||
|
|
||||||
virtual void Init(
|
protected:
|
||||||
StagePtr prev,
|
void Update(Duration dt) override;
|
||||||
StagePtr next
|
|
||||||
) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
virtual void Init(StagePtr prev, StagePtr next) override;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 盒状过渡动画
|
* @brief 位移过渡动画
|
||||||
* @details 前一场景以盒状收缩至消失,后一场景以盒状扩大
|
* @details 两场景以位移的方式切换
|
||||||
*/
|
*/
|
||||||
class BoxTransition
|
class MoveTransition : public Transition
|
||||||
: public Transition
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/**
|
||||||
/**
|
* \~chinese
|
||||||
* \~chinese
|
* @brief 位移方式
|
||||||
* @brief 构建盒状过渡动画
|
*/
|
||||||
* @param duration 动画时长
|
enum class Type : int
|
||||||
*/
|
{
|
||||||
explicit BoxTransition(
|
Up, ///< 上移
|
||||||
Duration duration
|
Down, ///< 下移
|
||||||
);
|
Left, ///< 左移
|
||||||
|
Right ///< 右移
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
void Update(Duration dt) override;
|
* \~chinese
|
||||||
|
* @brief 位移过渡动画
|
||||||
|
* @param duration 动画时长
|
||||||
|
* @param type 位移方式
|
||||||
|
*/
|
||||||
|
explicit MoveTransition(Duration duration, Type type);
|
||||||
|
|
||||||
virtual void Init(
|
protected:
|
||||||
StagePtr prev,
|
void Update(Duration dt) override;
|
||||||
StagePtr next
|
|
||||||
) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
virtual void Init(StagePtr prev, StagePtr next) override;
|
||||||
|
|
||||||
/**
|
void Reset() override;
|
||||||
* \~chinese
|
|
||||||
* @brief 位移过渡动画
|
|
||||||
* @details 两场景以位移的方式切换
|
|
||||||
*/
|
|
||||||
class MoveTransition
|
|
||||||
: public Transition
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 位移方式
|
|
||||||
*/
|
|
||||||
enum class Type : int
|
|
||||||
{
|
|
||||||
Up, ///< 上移
|
|
||||||
Down, ///< 下移
|
|
||||||
Left, ///< 左移
|
|
||||||
Right ///< 右移
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
private:
|
||||||
* \~chinese
|
Type type_;
|
||||||
* @brief 位移过渡动画
|
Point pos_delta_;
|
||||||
* @param duration 动画时长
|
Point start_pos_;
|
||||||
* @param type 位移方式
|
};
|
||||||
*/
|
|
||||||
explicit MoveTransition(
|
|
||||||
Duration duration,
|
|
||||||
Type type
|
|
||||||
);
|
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
void Update(Duration dt) override;
|
* \~chinese
|
||||||
|
* @brief 旋转过渡动画
|
||||||
|
* @details 前一场景以旋转方式收缩至消失,后一场景以旋转方式扩大
|
||||||
|
*/
|
||||||
|
class RotationTransition : public Transition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 构建旋转过渡动画
|
||||||
|
* @param duration 动画时长
|
||||||
|
* @param rotation 旋转度数
|
||||||
|
*/
|
||||||
|
explicit RotationTransition(Duration duration, float rotation = 360);
|
||||||
|
|
||||||
virtual void Init(
|
protected:
|
||||||
StagePtr prev,
|
void Update(Duration dt) override;
|
||||||
StagePtr next
|
|
||||||
) override;
|
|
||||||
|
|
||||||
void Reset() override;
|
virtual void Init(StagePtr prev, StagePtr next) override;
|
||||||
|
|
||||||
private:
|
void Reset() override;
|
||||||
Type type_;
|
|
||||||
Point pos_delta_;
|
|
||||||
Point start_pos_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
private:
|
||||||
/**
|
float rotation_;
|
||||||
* \~chinese
|
};
|
||||||
* @brief 旋转过渡动画
|
} // namespace kiwano
|
||||||
* @details 前一场景以旋转方式收缩至消失,后一场景以旋转方式扩大
|
|
||||||
*/
|
|
||||||
class RotationTransition
|
|
||||||
: public Transition
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 构建旋转过渡动画
|
|
||||||
* @param duration 动画时长
|
|
||||||
* @param rotation 旋转度数
|
|
||||||
*/
|
|
||||||
explicit RotationTransition(
|
|
||||||
Duration duration,
|
|
||||||
float rotation = 360
|
|
||||||
);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void Update(Duration dt) override;
|
|
||||||
|
|
||||||
virtual void Init(
|
|
||||||
StagePtr prev,
|
|
||||||
StagePtr next
|
|
||||||
) override;
|
|
||||||
|
|
||||||
void Reset() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float rotation_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -18,96 +18,91 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/action/Action.h>
|
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
|
#include <kiwano/2d/action/Action.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Action::Action()
|
Action::Action()
|
||||||
: running_(true)
|
: running_(true)
|
||||||
, detach_target_(false)
|
, detach_target_(false)
|
||||||
, loops_done_(0)
|
, loops_done_(0)
|
||||||
, loops_(0)
|
, loops_(0)
|
||||||
, status_(Status::NotStarted)
|
, status_(Status::NotStarted)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Action::~Action()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Action::Init(Actor* target)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Action::Update(Actor* target, Duration dt)
|
|
||||||
{
|
|
||||||
Complete(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Action::UpdateStep(Actor* target, Duration dt)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(target != nullptr && "Action target should NOT be nullptr!");
|
|
||||||
|
|
||||||
elapsed_ += dt;
|
|
||||||
|
|
||||||
if (status_ == Status::NotStarted)
|
|
||||||
{
|
|
||||||
status_ = delay_.IsZero() ? Status::Started : Status::Delayed;
|
|
||||||
Init(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (status_)
|
|
||||||
{
|
|
||||||
case Status::Delayed:
|
|
||||||
if (elapsed_ >= delay_)
|
|
||||||
{
|
|
||||||
status_ = Status::Started;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Status::Started:
|
|
||||||
Update(target, dt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status_ == Status::Done)
|
|
||||||
{
|
|
||||||
if (cb_done_)
|
|
||||||
cb_done_(target);
|
|
||||||
|
|
||||||
if (detach_target_)
|
|
||||||
target->RemoveFromParent();
|
|
||||||
|
|
||||||
status_ = Status::Removeable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Action::Complete(Actor* target)
|
|
||||||
{
|
|
||||||
if (cb_loop_done_)
|
|
||||||
cb_loop_done_(target);
|
|
||||||
|
|
||||||
if (loops_ >= 0
|
|
||||||
&& loops_done_ >= loops_)
|
|
||||||
{
|
|
||||||
Done();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Init(target); // reinit when a loop is done
|
|
||||||
}
|
|
||||||
|
|
||||||
++loops_done_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Action::Restart(Actor* target)
|
|
||||||
{
|
|
||||||
status_ = Status::NotStarted;
|
|
||||||
elapsed_ = 0;
|
|
||||||
loops_done_ = 0;
|
|
||||||
|
|
||||||
Init(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action::~Action() {}
|
||||||
|
|
||||||
|
void Action::Init(Actor* target) {}
|
||||||
|
|
||||||
|
void Action::Update(Actor* target, Duration dt)
|
||||||
|
{
|
||||||
|
Complete(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Action::UpdateStep(Actor* target, Duration dt)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(target != nullptr && "Action target should NOT be nullptr!");
|
||||||
|
|
||||||
|
elapsed_ += dt;
|
||||||
|
|
||||||
|
if (status_ == Status::NotStarted)
|
||||||
|
{
|
||||||
|
status_ = delay_.IsZero() ? Status::Started : Status::Delayed;
|
||||||
|
Init(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status_)
|
||||||
|
{
|
||||||
|
case Status::Delayed:
|
||||||
|
if (elapsed_ >= delay_)
|
||||||
|
{
|
||||||
|
status_ = Status::Started;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Status::Started:
|
||||||
|
Update(target, dt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status_ == Status::Done)
|
||||||
|
{
|
||||||
|
if (cb_done_)
|
||||||
|
cb_done_(target);
|
||||||
|
|
||||||
|
if (detach_target_)
|
||||||
|
target->RemoveFromParent();
|
||||||
|
|
||||||
|
status_ = Status::Removeable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Action::Complete(Actor* target)
|
||||||
|
{
|
||||||
|
if (cb_loop_done_)
|
||||||
|
cb_loop_done_(target);
|
||||||
|
|
||||||
|
if (loops_ >= 0 && loops_done_ >= loops_)
|
||||||
|
{
|
||||||
|
Done();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Init(target); // reinit when a loop is done
|
||||||
|
}
|
||||||
|
|
||||||
|
++loops_done_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Action::Restart(Actor* target)
|
||||||
|
{
|
||||||
|
status_ = Status::NotStarted;
|
||||||
|
elapsed_ = 0;
|
||||||
|
loops_done_ = 0;
|
||||||
|
|
||||||
|
Init(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,272 +19,271 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/common.h>
|
#include <kiwano/core/Common.h>
|
||||||
#include <kiwano/core/time.h>
|
|
||||||
#include <kiwano/core/SmartPtr.hpp>
|
|
||||||
#include <kiwano/core/ObjectBase.h>
|
#include <kiwano/core/ObjectBase.h>
|
||||||
|
#include <kiwano/core/SmartPtr.hpp>
|
||||||
|
#include <kiwano/core/Time.h>
|
||||||
#include <kiwano/math/math.h>
|
#include <kiwano/math/math.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
class Actor;
|
class Actor;
|
||||||
class ActionManager;
|
class ActionManager;
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(Action);
|
KGE_DECLARE_SMART_PTR(Action);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* \defgroup Actions 动画
|
* \defgroup Actions 动画
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actions
|
* \addtogroup Actions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画
|
/// @brief 动画
|
||||||
class KGE_API Action
|
class KGE_API Action
|
||||||
: public ObjectBase
|
: public virtual ObjectBase
|
||||||
, protected IntrusiveListItem<ActionPtr>
|
, protected IntrusiveListItem<ActionPtr>
|
||||||
{
|
{
|
||||||
friend class ActionManager;
|
friend class ActionManager;
|
||||||
friend class ActionGroup;
|
friend class ActionGroup;
|
||||||
friend IntrusiveList<ActionPtr>;
|
friend IntrusiveList<ActionPtr>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画结束时的回调函数
|
/// @brief 动画结束时的回调函数
|
||||||
using DoneCallback = Function<void(Actor* /* target */)>;
|
using DoneCallback = Function<void(Actor* /* target */)>;
|
||||||
|
|
||||||
Action();
|
Action();
|
||||||
|
|
||||||
virtual ~Action();
|
virtual ~Action();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 继续动画
|
/// @brief 继续动画
|
||||||
void Resume();
|
void Resume();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 暂停动画
|
/// @brief 暂停动画
|
||||||
void Pause();
|
void Pause();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 停止动画
|
/// @brief 停止动画
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画延时
|
/// @brief 设置动画延时
|
||||||
void SetDelay(Duration delay);
|
void SetDelay(Duration delay);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置循环次数
|
/// @brief 设置循环次数
|
||||||
/// @param loops 循环次数,-1 为永久循环
|
/// @param loops 循环次数,-1 为永久循环
|
||||||
void SetLoops(int loops);
|
void SetLoops(int loops);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画结束时移除目标角色
|
/// @brief 动画结束时移除目标角色
|
||||||
void RemoveTargetWhenDone();
|
void RemoveTargetWhenDone();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画结束时的回调函数
|
/// @brief 设置动画结束时的回调函数
|
||||||
void SetDoneCallback(DoneCallback const& cb);
|
void SetDoneCallback(DoneCallback const& cb);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画循环结束时的回调函数
|
/// @brief 设置动画循环结束时的回调函数
|
||||||
void SetLoopDoneCallback(DoneCallback const& cb);
|
void SetLoopDoneCallback(DoneCallback const& cb);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画的拷贝
|
/// @brief 获取动画的拷贝
|
||||||
virtual ActionPtr Clone() const = 0;
|
virtual ActionPtr Clone() const = 0;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画的倒转
|
/// @brief 获取动画的倒转
|
||||||
virtual ActionPtr Reverse() const = 0;
|
virtual ActionPtr Reverse() const = 0;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画的运行状态
|
/// @brief 获取动画的运行状态
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画的循环次数
|
/// @brief 获取动画的循环次数
|
||||||
int GetLoops() const;
|
int GetLoops() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画的延时
|
/// @brief 获取动画的延时
|
||||||
Duration GetDelay() const;
|
Duration GetDelay() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画结束时的回调函数
|
/// @brief 获取动画结束时的回调函数
|
||||||
DoneCallback GetDoneCallback() const;
|
DoneCallback GetDoneCallback() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画循环结束时的回调函数
|
/// @brief 获取动画循环结束时的回调函数
|
||||||
DoneCallback GetLoopDoneCallback() const;
|
DoneCallback GetLoopDoneCallback() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 初始化动画
|
/// @brief 初始化动画
|
||||||
virtual void Init(Actor* target);
|
virtual void Init(Actor* target);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 更新动画
|
/// @brief 更新动画
|
||||||
virtual void Update(Actor* target, Duration dt);
|
virtual void Update(Actor* target, Duration dt);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 更新一个时间步
|
/// @brief 更新一个时间步
|
||||||
void UpdateStep(Actor* target, Duration dt);
|
void UpdateStep(Actor* target, Duration dt);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 完成动画
|
/// @brief 完成动画
|
||||||
void Complete(Actor* target);
|
void Complete(Actor* target);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 重新开始动画
|
/// @brief 重新开始动画
|
||||||
void Restart(Actor* target);
|
void Restart(Actor* target);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画状态
|
/// @brief 动画状态
|
||||||
enum class Status
|
enum class Status
|
||||||
{
|
{
|
||||||
NotStarted, ///< 未开始
|
NotStarted, ///< 未开始
|
||||||
Delayed, ///< 等待延时
|
Delayed, ///< 等待延时
|
||||||
Started, ///< 已开始
|
Started, ///< 已开始
|
||||||
Done, ///< 已结束
|
Done, ///< 已结束
|
||||||
Removeable ///< 可移除
|
Removeable ///< 可移除
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取动画状态
|
/// @brief 获取动画状态
|
||||||
Status GetStatus() const;
|
Status GetStatus() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取消逝时间
|
/// @brief 获取消逝时间
|
||||||
Duration GetElapsed() const;
|
Duration GetElapsed() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取完成的循环次数
|
/// @brief 获取完成的循环次数
|
||||||
int GetLoopsDone() const;
|
int GetLoopsDone() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 结束动画
|
/// @brief 结束动画
|
||||||
void Done();
|
void Done();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否已结束
|
/// @brief 是否已结束
|
||||||
bool IsDone() const;
|
bool IsDone() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 是否可移除
|
/// @brief 是否可移除
|
||||||
bool IsRemoveable() const;
|
bool IsRemoveable() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Status status_;
|
Status status_;
|
||||||
bool running_;
|
bool running_;
|
||||||
bool detach_target_;
|
bool detach_target_;
|
||||||
int loops_;
|
int loops_;
|
||||||
int loops_done_;
|
int loops_done_;
|
||||||
Duration delay_;
|
Duration delay_;
|
||||||
Duration elapsed_;
|
Duration elapsed_;
|
||||||
DoneCallback cb_done_;
|
DoneCallback cb_done_;
|
||||||
DoneCallback cb_loop_done_;
|
DoneCallback cb_loop_done_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
inline void Action::Resume()
|
||||||
inline void Action::Resume()
|
{
|
||||||
{
|
running_ = true;
|
||||||
running_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::Pause()
|
|
||||||
{
|
|
||||||
running_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::Stop()
|
|
||||||
{
|
|
||||||
Done();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::SetDelay(Duration delay)
|
|
||||||
{
|
|
||||||
delay_ = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::SetLoops(int loops)
|
|
||||||
{
|
|
||||||
loops_ = loops;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::RemoveTargetWhenDone()
|
|
||||||
{
|
|
||||||
detach_target_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::SetDoneCallback(DoneCallback const& cb)
|
|
||||||
{
|
|
||||||
cb_done_ = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::SetLoopDoneCallback(DoneCallback const& cb)
|
|
||||||
{
|
|
||||||
cb_loop_done_ = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Action::Done()
|
|
||||||
{
|
|
||||||
status_ = Status::Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Action::Status Action::GetStatus() const
|
|
||||||
{
|
|
||||||
return status_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Action::IsRunning() const
|
|
||||||
{
|
|
||||||
return running_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Action::IsDone() const
|
|
||||||
{
|
|
||||||
return status_ == Status::Done || status_ == Status::Removeable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Action::IsRemoveable() const
|
|
||||||
{
|
|
||||||
return status_ == Status::Removeable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Action::GetLoops() const
|
|
||||||
{
|
|
||||||
return loops_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Duration Action::GetDelay() const
|
|
||||||
{
|
|
||||||
return delay_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Duration Action::GetElapsed() const
|
|
||||||
{
|
|
||||||
return elapsed_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Action::GetLoopsDone() const
|
|
||||||
{
|
|
||||||
return loops_done_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Action::DoneCallback Action::GetDoneCallback() const
|
|
||||||
{
|
|
||||||
return cb_done_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Action::DoneCallback Action::GetLoopDoneCallback() const
|
|
||||||
{
|
|
||||||
return cb_loop_done_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Action::Pause()
|
||||||
|
{
|
||||||
|
running_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::Stop()
|
||||||
|
{
|
||||||
|
Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::SetDelay(Duration delay)
|
||||||
|
{
|
||||||
|
delay_ = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::SetLoops(int loops)
|
||||||
|
{
|
||||||
|
loops_ = loops;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::RemoveTargetWhenDone()
|
||||||
|
{
|
||||||
|
detach_target_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::SetDoneCallback(DoneCallback const& cb)
|
||||||
|
{
|
||||||
|
cb_done_ = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::SetLoopDoneCallback(DoneCallback const& cb)
|
||||||
|
{
|
||||||
|
cb_loop_done_ = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Action::Done()
|
||||||
|
{
|
||||||
|
status_ = Status::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Action::Status Action::GetStatus() const
|
||||||
|
{
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Action::IsRunning() const
|
||||||
|
{
|
||||||
|
return running_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Action::IsDone() const
|
||||||
|
{
|
||||||
|
return status_ == Status::Done || status_ == Status::Removeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Action::IsRemoveable() const
|
||||||
|
{
|
||||||
|
return status_ == Status::Removeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Action::GetLoops() const
|
||||||
|
{
|
||||||
|
return loops_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Duration Action::GetDelay() const
|
||||||
|
{
|
||||||
|
return delay_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Duration Action::GetElapsed() const
|
||||||
|
{
|
||||||
|
return elapsed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Action::GetLoopsDone() const
|
||||||
|
{
|
||||||
|
return loops_done_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Action::DoneCallback Action::GetDoneCallback() const
|
||||||
|
{
|
||||||
|
return cb_done_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Action::DoneCallback Action::GetLoopDoneCallback() const
|
||||||
|
{
|
||||||
|
return cb_loop_done_;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,19 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
ActionDelay::ActionDelay(Duration delay)
|
ActionDelay::ActionDelay(Duration delay)
|
||||||
{
|
{
|
||||||
SetDelay(delay);
|
SetDelay(delay);
|
||||||
}
|
|
||||||
|
|
||||||
ActionPtr ActionDelay::Clone() const
|
|
||||||
{
|
|
||||||
return new ActionDelay(GetDelay());
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionPtr ActionDelay::Reverse() const
|
|
||||||
{
|
|
||||||
return new ActionDelay(GetDelay());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionPtr ActionDelay::Clone() const
|
||||||
|
{
|
||||||
|
return new ActionDelay(GetDelay());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionPtr ActionDelay::Reverse() const
|
||||||
|
{
|
||||||
|
return new ActionDelay(GetDelay());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,32 +23,29 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actions
|
* \addtogroup Actions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 延时动画
|
/// @brief 延时动画
|
||||||
class KGE_API ActionDelay
|
class KGE_API ActionDelay : public Action
|
||||||
: public Action
|
{
|
||||||
{
|
public:
|
||||||
public:
|
/// \~chinese
|
||||||
/// \~chinese
|
/// @brief 构建延时动画
|
||||||
/// @brief 构建延时动画
|
/// @param delay 延时时长
|
||||||
/// @param delay 延时时长
|
ActionDelay(Duration delay);
|
||||||
ActionDelay(
|
|
||||||
Duration delay
|
|
||||||
);
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取该动画的拷贝对象
|
/// @brief 获取该动画的拷贝对象
|
||||||
ActionPtr Clone() const override;
|
ActionPtr Clone() const override;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取该动画的倒转
|
/// @brief 获取该动画的倒转
|
||||||
ActionPtr Reverse() const override;
|
ActionPtr Reverse() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,131 +18,129 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/action/ActionGroup.h>
|
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
|
#include <kiwano/2d/action/ActionGroup.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
// ActionGroup
|
// ActionGroup
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
|
|
||||||
ActionGroup::ActionGroup()
|
|
||||||
: sequence_(true)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionGroup::ActionGroup(Vector<ActionPtr> const& actions, bool sequence)
|
|
||||||
: sequence_(sequence)
|
|
||||||
{
|
|
||||||
this->Add(actions);
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionGroup::~ActionGroup()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionGroup::Init(Actor* target)
|
|
||||||
{
|
|
||||||
if (actions_.empty())
|
|
||||||
{
|
|
||||||
Done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_ = actions_.first_item();
|
|
||||||
current_->Restart(target); // init first action
|
|
||||||
|
|
||||||
if (!sequence_)
|
|
||||||
{
|
|
||||||
// init all actions
|
|
||||||
for (; current_; current_ = current_->next_item())
|
|
||||||
{
|
|
||||||
current_->Restart(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionGroup::Update(Actor* target, Duration dt)
|
|
||||||
{
|
|
||||||
if (sequence_)
|
|
||||||
{
|
|
||||||
if (current_)
|
|
||||||
{
|
|
||||||
current_->UpdateStep(target, dt);
|
|
||||||
|
|
||||||
if (current_->IsDone())
|
|
||||||
{
|
|
||||||
current_ = current_->next_item();
|
|
||||||
|
|
||||||
if (current_)
|
|
||||||
current_->Restart(target); // init next action
|
|
||||||
else
|
|
||||||
Complete(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool done = true;
|
|
||||||
for (current_ = actions_.first_item(); current_; current_ = current_->next_item())
|
|
||||||
{
|
|
||||||
if (!current_->IsDone())
|
|
||||||
{
|
|
||||||
done = false;
|
|
||||||
current_->UpdateStep(target, dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (done)
|
|
||||||
{
|
|
||||||
Complete(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionGroup::Add(ActionPtr action)
|
|
||||||
{
|
|
||||||
if (action)
|
|
||||||
{
|
|
||||||
actions_.push_back(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionGroup::Add(Vector<ActionPtr> const& actions)
|
|
||||||
{
|
|
||||||
for (const auto& action : actions)
|
|
||||||
Add(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionPtr ActionGroup::Clone() const
|
|
||||||
{
|
|
||||||
auto group = new (std::nothrow) ActionGroup();
|
|
||||||
if (group)
|
|
||||||
{
|
|
||||||
for (auto action = actions_.first_item(); action; action = action->next_item())
|
|
||||||
{
|
|
||||||
if (action)
|
|
||||||
{
|
|
||||||
group->Add(action->Clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionPtr ActionGroup::Reverse() const
|
|
||||||
{
|
|
||||||
auto group = new (std::nothrow) ActionGroup();
|
|
||||||
if (group && !actions_.empty())
|
|
||||||
{
|
|
||||||
for (auto action = actions_.last_item(); action; action = action->prev_item())
|
|
||||||
{
|
|
||||||
group->Add(action->Reverse());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ActionGroup::ActionGroup()
|
||||||
|
: sequence_(true)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionGroup::ActionGroup(Vector<ActionPtr> const& actions, bool sequence)
|
||||||
|
: sequence_(sequence)
|
||||||
|
{
|
||||||
|
this->Add(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionGroup::~ActionGroup() {}
|
||||||
|
|
||||||
|
void ActionGroup::Init(Actor* target)
|
||||||
|
{
|
||||||
|
if (actions_.empty())
|
||||||
|
{
|
||||||
|
Done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_ = actions_.first_item();
|
||||||
|
current_->Restart(target); // init first action
|
||||||
|
|
||||||
|
if (!sequence_)
|
||||||
|
{
|
||||||
|
// init all actions
|
||||||
|
for (; current_; current_ = current_->next_item())
|
||||||
|
{
|
||||||
|
current_->Restart(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionGroup::Update(Actor* target, Duration dt)
|
||||||
|
{
|
||||||
|
if (sequence_)
|
||||||
|
{
|
||||||
|
if (current_)
|
||||||
|
{
|
||||||
|
current_->UpdateStep(target, dt);
|
||||||
|
|
||||||
|
if (current_->IsDone())
|
||||||
|
{
|
||||||
|
current_ = current_->next_item();
|
||||||
|
|
||||||
|
if (current_)
|
||||||
|
current_->Restart(target); // init next action
|
||||||
|
else
|
||||||
|
Complete(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool done = true;
|
||||||
|
for (current_ = actions_.first_item(); current_; current_ = current_->next_item())
|
||||||
|
{
|
||||||
|
if (!current_->IsDone())
|
||||||
|
{
|
||||||
|
done = false;
|
||||||
|
current_->UpdateStep(target, dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
{
|
||||||
|
Complete(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionGroup::Add(ActionPtr action)
|
||||||
|
{
|
||||||
|
if (action)
|
||||||
|
{
|
||||||
|
actions_.push_back(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionGroup::Add(Vector<ActionPtr> const& actions)
|
||||||
|
{
|
||||||
|
for (const auto& action : actions)
|
||||||
|
Add(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionPtr ActionGroup::Clone() const
|
||||||
|
{
|
||||||
|
auto group = new (std::nothrow) ActionGroup();
|
||||||
|
if (group)
|
||||||
|
{
|
||||||
|
for (auto action = actions_.first_item(); action; action = action->next_item())
|
||||||
|
{
|
||||||
|
if (action)
|
||||||
|
{
|
||||||
|
group->Add(action->Clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionPtr ActionGroup::Reverse() const
|
||||||
|
{
|
||||||
|
auto group = new (std::nothrow) ActionGroup();
|
||||||
|
if (group && !actions_.empty())
|
||||||
|
{
|
||||||
|
for (auto action = actions_.last_item(); action; action = action->prev_item())
|
||||||
|
{
|
||||||
|
group->Add(action->Reverse());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,66 +23,68 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SMART_PTR(ActionGroup);
|
KGE_DECLARE_SMART_PTR(ActionGroup);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actions
|
* \addtogroup Actions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画组合
|
/// @brief 动画组合
|
||||||
class KGE_API ActionGroup
|
class KGE_API ActionGroup : public Action
|
||||||
: public Action
|
{
|
||||||
{
|
public:
|
||||||
public:
|
using ActionList = IntrusiveList<ActionPtr>;
|
||||||
using ActionList = IntrusiveList<ActionPtr>;
|
|
||||||
|
|
||||||
ActionGroup();
|
ActionGroup();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画组合
|
/// @brief 动画组合
|
||||||
/// @param actions 动画集合
|
/// @param actions 动画集合
|
||||||
/// @param sequence 动画按顺序依次执行或同时执行
|
/// @param sequence 动画按顺序依次执行或同时执行
|
||||||
explicit ActionGroup(Vector<ActionPtr> const& actions, bool sequence = true);
|
explicit ActionGroup(Vector<ActionPtr> const& actions, bool sequence = true);
|
||||||
|
|
||||||
virtual ~ActionGroup();
|
virtual ~ActionGroup();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加动画
|
/// @brief 添加动画
|
||||||
/// @param action 动画
|
/// @param action 动画
|
||||||
void Add(ActionPtr action);
|
void Add(ActionPtr action);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加多个动画
|
/// @brief 添加多个动画
|
||||||
/// @param actions 动画集合
|
/// @param actions 动画集合
|
||||||
void Add(Vector<ActionPtr> const& actions);
|
void Add(Vector<ActionPtr> const& actions);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取所有动画
|
/// @brief 获取所有动画
|
||||||
ActionList const& GetActions() const;
|
ActionList const& GetActions() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取该动画的拷贝对象
|
/// @brief 获取该动画的拷贝对象
|
||||||
ActionPtr Clone() const override;
|
ActionPtr Clone() const override;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取该动画的倒转
|
/// @brief 获取该动画的倒转
|
||||||
ActionPtr Reverse() const override;
|
ActionPtr Reverse() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Init(Actor* target) override;
|
void Init(Actor* target) override;
|
||||||
|
|
||||||
void Update(Actor* target, Duration dt) override;
|
void Update(Actor* target, Duration dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool sequence_;
|
bool sequence_;
|
||||||
ActionPtr current_;
|
ActionPtr current_;
|
||||||
ActionList actions_;
|
ActionList actions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline ActionGroup::ActionList const& ActionGroup::GetActions() const { return actions_; }
|
|
||||||
|
|
||||||
|
inline ActionGroup::ActionList const& ActionGroup::GetActions() const
|
||||||
|
{
|
||||||
|
return actions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -19,293 +19,354 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/2d/action/ActionTween.h>
|
|
||||||
#include <kiwano/2d/action/ActionWalk.h>
|
|
||||||
#include <kiwano/2d/action/ActionDelay.h>
|
#include <kiwano/2d/action/ActionDelay.h>
|
||||||
#include <kiwano/2d/action/ActionGroup.h>
|
#include <kiwano/2d/action/ActionGroup.h>
|
||||||
|
#include <kiwano/2d/action/ActionTween.h>
|
||||||
|
#include <kiwano/2d/action/ActionWalk.h>
|
||||||
#include <kiwano/2d/action/Animation.h>
|
#include <kiwano/2d/action/Animation.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actions
|
* \addtogroup Actions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画辅助类
|
/// @brief 动画辅助类
|
||||||
struct ActionHelper
|
struct ActionHelper
|
||||||
{
|
{
|
||||||
using DoneCallback = Action::DoneCallback;
|
using DoneCallback = Action::DoneCallback;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置循环次数
|
/// @brief 设置循环次数
|
||||||
inline ActionHelper& SetLoops(int loops) { core->SetLoops(loops); return (*this); }
|
inline ActionHelper& SetLoops(int loops)
|
||||||
|
{
|
||||||
|
core->SetLoops(loops);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画延迟
|
/// @brief 设置动画延迟
|
||||||
inline ActionHelper& SetDelay(Duration delay) { core->SetDelay(delay); return (*this); }
|
inline ActionHelper& SetDelay(Duration delay)
|
||||||
|
{
|
||||||
|
core->SetDelay(delay);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画结束回调函数
|
/// @brief 设置动画结束回调函数
|
||||||
inline ActionHelper& SetDoneCallback(DoneCallback const& cb) { core->SetDoneCallback(cb); return (*this); }
|
inline ActionHelper& SetDoneCallback(DoneCallback const& cb)
|
||||||
|
{
|
||||||
|
core->SetDoneCallback(cb);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画循环结束时的回调函数
|
/// @brief 设置动画循环结束时的回调函数
|
||||||
inline ActionHelper& SetLoopDoneCallback(DoneCallback const& cb) { core->SetLoopDoneCallback(cb); return (*this); }
|
inline ActionHelper& SetLoopDoneCallback(DoneCallback const& cb)
|
||||||
|
{
|
||||||
|
core->SetLoopDoneCallback(cb);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画结束时移除目标角色
|
/// @brief 动画结束时移除目标角色
|
||||||
inline ActionHelper& RemoveTargetWhenDone() { core->RemoveTargetWhenDone(); return (*this); }
|
inline ActionHelper& RemoveTargetWhenDone()
|
||||||
|
{
|
||||||
|
core->RemoveTargetWhenDone();
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置名称
|
/// @brief 设置名称
|
||||||
inline ActionHelper& SetName(String const& name) { core->SetName(name); return (*this); }
|
inline ActionHelper& SetName(String const& name)
|
||||||
|
{
|
||||||
|
core->SetName(name);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取指针
|
/// @brief 获取指针
|
||||||
inline ActionPtr Get() const { return core; }
|
inline ActionPtr Get() const
|
||||||
|
{
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
inline ActionHelper(ActionPtr core) : core(core) {}
|
inline ActionHelper(ActionPtr core)
|
||||||
|
: core(core)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
inline operator ActionPtr() const { return core; }
|
inline operator ActionPtr() const
|
||||||
|
{
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ActionPtr core;
|
ActionPtr core;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 补间动画辅助类
|
/// @brief 补间动画辅助类
|
||||||
struct TweenHelper
|
struct TweenHelper
|
||||||
{
|
{
|
||||||
using DoneCallback = Action::DoneCallback;
|
using DoneCallback = Action::DoneCallback;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画持续时长
|
/// @brief 设置动画持续时长
|
||||||
inline TweenHelper& SetDuration(Duration dur) { core->SetDuration(dur); return (*this); }
|
inline TweenHelper& SetDuration(Duration dur)
|
||||||
|
{
|
||||||
|
core->SetDuration(dur);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置循环次数
|
/// @brief 设置循环次数
|
||||||
inline TweenHelper& SetLoops(int loops) { core->SetLoops(loops); return (*this); }
|
inline TweenHelper& SetLoops(int loops)
|
||||||
|
{
|
||||||
|
core->SetLoops(loops);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置缓动函数
|
/// @brief 设置缓动函数
|
||||||
inline TweenHelper& SetEaseFunc(EaseFunc ease) { core->SetEaseFunc(ease); return (*this); }
|
inline TweenHelper& SetEaseFunc(EaseFunc ease)
|
||||||
|
{
|
||||||
|
core->SetEaseFunc(ease);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画延迟
|
/// @brief 设置动画延迟
|
||||||
inline TweenHelper& SetDelay(Duration delay) { core->SetDelay(delay); return (*this); }
|
inline TweenHelper& SetDelay(Duration delay)
|
||||||
|
{
|
||||||
|
core->SetDelay(delay);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画结束回调函数
|
/// @brief 设置动画结束回调函数
|
||||||
inline TweenHelper& SetDoneCallback(DoneCallback const& cb) { core->SetDoneCallback(cb); return (*this); }
|
inline TweenHelper& SetDoneCallback(DoneCallback const& cb)
|
||||||
|
{
|
||||||
|
core->SetDoneCallback(cb);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置动画循环结束时的回调函数
|
/// @brief 设置动画循环结束时的回调函数
|
||||||
inline TweenHelper& SetLoopDoneCallback(DoneCallback const& cb) { core->SetLoopDoneCallback(cb); return (*this); }
|
inline TweenHelper& SetLoopDoneCallback(DoneCallback const& cb)
|
||||||
|
{
|
||||||
|
core->SetLoopDoneCallback(cb);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画结束时移除目标角色
|
/// @brief 动画结束时移除目标角色
|
||||||
inline TweenHelper& RemoveTargetWhenDone() { core->RemoveTargetWhenDone(); return (*this); }
|
inline TweenHelper& RemoveTargetWhenDone()
|
||||||
|
{
|
||||||
|
core->RemoveTargetWhenDone();
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 设置名称
|
/// @brief 设置名称
|
||||||
inline TweenHelper& SetName(String const& name) { core->SetName(name); return (*this); }
|
inline TweenHelper& SetName(String const& name)
|
||||||
|
{
|
||||||
|
core->SetName(name);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取指针
|
/// @brief 获取指针
|
||||||
inline ActionTweenPtr Get() const { return core; }
|
inline ActionTweenPtr Get() const
|
||||||
|
{
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
inline TweenHelper(ActionTweenPtr core) : core(core) {}
|
inline TweenHelper(ActionTweenPtr core)
|
||||||
|
: core(core)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
inline operator ActionPtr() const { return core; }
|
inline operator ActionPtr() const
|
||||||
|
{
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
inline operator ActionTweenPtr() const { return core; }
|
inline operator ActionTweenPtr() const
|
||||||
|
{
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ActionTweenPtr core;
|
ActionTweenPtr core;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画构造器
|
/// @brief 动画构造器
|
||||||
struct Tween
|
struct Tween
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造相对位移动画
|
/// @brief 构造相对位移动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param vector 移动向量
|
/// @param vector 移动向量
|
||||||
static inline TweenHelper
|
static inline TweenHelper MoveBy(Duration dur, Point const& vector)
|
||||||
MoveBy(Duration dur, Point const& vector)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionMoveBy(dur, vector));
|
||||||
return TweenHelper(new kiwano::ActionMoveBy(dur, vector));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造位移动画
|
/// @brief 构造位移动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param pos 目的坐标
|
/// @param pos 目的坐标
|
||||||
static inline TweenHelper
|
static inline TweenHelper MoveTo(Duration dur, Point const& pos)
|
||||||
MoveTo(Duration dur, Point const& pos)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionMoveTo(dur, pos));
|
||||||
return TweenHelper(new kiwano::ActionMoveTo(dur, pos));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造相对跳跃动画
|
/// @brief 构造相对跳跃动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param vec 跳跃位移向量
|
/// @param vec 跳跃位移向量
|
||||||
/// @param height 跳跃高度
|
/// @param height 跳跃高度
|
||||||
/// @param jumps 跳跃次数
|
/// @param jumps 跳跃次数
|
||||||
static inline TweenHelper
|
static inline TweenHelper JumpBy(Duration duration, Vec2 const& vec, float height, int jumps = 1)
|
||||||
JumpBy(Duration duration, Vec2 const& vec, float height, int jumps = 1)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionJumpBy(duration, vec, height, jumps));
|
||||||
return TweenHelper(new kiwano::ActionJumpBy(duration, vec, height, jumps));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造跳跃动画
|
/// @brief 构造跳跃动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param pos 目的坐标
|
/// @param pos 目的坐标
|
||||||
/// @param height 跳跃高度
|
/// @param height 跳跃高度
|
||||||
/// @param jumps 跳跃次数
|
/// @param jumps 跳跃次数
|
||||||
static inline TweenHelper
|
static inline TweenHelper JumpTo(Duration duration, Point const& pos, float height, int jumps = 1)
|
||||||
JumpTo(Duration duration, Point const& pos, float height, int jumps = 1)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionJumpTo(duration, pos, height, jumps));
|
||||||
return TweenHelper(new kiwano::ActionJumpTo(duration, pos, height, jumps));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造相对缩放动画
|
/// @brief 构造相对缩放动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param scale_x 横向缩放相对变化值
|
/// @param scale_x 横向缩放相对变化值
|
||||||
/// @param scale_y 纵向缩放相对变化值
|
/// @param scale_y 纵向缩放相对变化值
|
||||||
static inline TweenHelper
|
static inline TweenHelper ScaleBy(Duration dur, float scale_x, float scale_y)
|
||||||
ScaleBy(Duration dur, float scale_x, float scale_y)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionScaleBy(dur, scale_x, scale_y));
|
||||||
return TweenHelper(new kiwano::ActionScaleBy(dur, scale_x, scale_y));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造缩放动画
|
/// @brief 构造缩放动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param scale_x 横向缩放目标值
|
/// @param scale_x 横向缩放目标值
|
||||||
/// @param scale_y 纵向缩放目标值
|
/// @param scale_y 纵向缩放目标值
|
||||||
static inline TweenHelper
|
static inline TweenHelper ScaleTo(Duration dur, float scale_x, float scale_y)
|
||||||
ScaleTo(Duration dur, float scale_x, float scale_y)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionScaleTo(dur, scale_x, scale_y));
|
||||||
return TweenHelper(new kiwano::ActionScaleTo(dur, scale_x, scale_y));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造透明度渐变动画
|
/// @brief 构造透明度渐变动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param opacity 目标透明度
|
/// @param opacity 目标透明度
|
||||||
static inline TweenHelper
|
static inline TweenHelper FadeTo(Duration dur, float opacity)
|
||||||
FadeTo(Duration dur, float opacity)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionFadeTo(dur, opacity));
|
||||||
return TweenHelper(new kiwano::ActionFadeTo(dur, opacity));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造淡入动画
|
/// @brief 构造淡入动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
static inline TweenHelper
|
static inline TweenHelper FadeIn(Duration dur)
|
||||||
FadeIn(Duration dur)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionFadeIn(dur));
|
||||||
return TweenHelper(new kiwano::ActionFadeIn(dur));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造淡出动画
|
/// @brief 构造淡出动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
static inline TweenHelper
|
static inline TweenHelper FadeOut(Duration dur)
|
||||||
FadeOut(Duration dur)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionFadeOut(dur));
|
||||||
return TweenHelper(new kiwano::ActionFadeOut(dur));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造相对旋转动画
|
/// @brief 构造相对旋转动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param rotation 角度相对变化值
|
/// @param rotation 角度相对变化值
|
||||||
static inline TweenHelper
|
static inline TweenHelper RotateBy(Duration dur, float rotation)
|
||||||
RotateBy(Duration dur, float rotation)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionRotateBy(dur, rotation));
|
||||||
return TweenHelper(new kiwano::ActionRotateBy(dur, rotation));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造旋转动画
|
/// @brief 构造旋转动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param rotation 目标角度
|
/// @param rotation 目标角度
|
||||||
static inline TweenHelper
|
static inline TweenHelper RotateTo(Duration dur, float rotation)
|
||||||
RotateTo(Duration dur, float rotation)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionRotateTo(dur, rotation));
|
||||||
return TweenHelper(new kiwano::ActionRotateTo(dur, rotation));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造路径行走动画
|
/// @brief 构造路径行走动画
|
||||||
/// @param duration 持续时长
|
/// @param duration 持续时长
|
||||||
/// @param path 路径几何形状
|
/// @param path 路径几何形状
|
||||||
/// @param rotating 是否沿路径切线方向旋转
|
/// @param rotating 是否沿路径切线方向旋转
|
||||||
/// @param start 路径起点(百分比)
|
/// @param start 路径起点(百分比)
|
||||||
/// @param end 路径终点(百分比)
|
/// @param end 路径终点(百分比)
|
||||||
static inline TweenHelper
|
static inline TweenHelper Walk(Duration duration, Geometry const& path, bool rotating = false, float start = 0.f,
|
||||||
Walk(Duration duration, Geometry const& path, bool rotating = false, float start = 0.f, float end = 1.f)
|
float end = 1.f)
|
||||||
{
|
{
|
||||||
return TweenHelper(new kiwano::ActionWalk(duration, path, rotating, start, end));
|
return TweenHelper(new kiwano::ActionWalk(duration, path, rotating, start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构建帧动画
|
/// @brief 构建帧动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param[in] frame_seq 序列帧
|
/// @param[in] frame_seq 序列帧
|
||||||
static inline TweenHelper
|
static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames)
|
||||||
Animation(Duration dur, FrameSequencePtr frames)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::Animation(dur, frames));
|
||||||
return TweenHelper(new kiwano::Animation(dur, frames));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构造自定义动画
|
/// @brief 构造自定义动画
|
||||||
/// @param duration 动画时长
|
/// @param duration 动画时长
|
||||||
/// @param tween_func 动画回调函数
|
/// @param tween_func 动画回调函数
|
||||||
static inline TweenHelper
|
static inline TweenHelper Custom(Duration dur, ActionCustom::TweenFunc tween_func)
|
||||||
Custom(Duration dur, ActionCustom::TweenFunc tween_func)
|
{
|
||||||
{
|
return TweenHelper(new kiwano::ActionCustom(dur, tween_func));
|
||||||
return TweenHelper(new kiwano::ActionCustom(dur, tween_func));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 构建延时动画
|
/// @brief 构建延时动画
|
||||||
/// @param delay 延时时长
|
/// @param delay 延时时长
|
||||||
static inline ActionHelper
|
static inline ActionHelper Delay(Duration delay)
|
||||||
Delay(Duration delay)
|
{
|
||||||
{
|
return ActionHelper(new kiwano::ActionDelay(delay));
|
||||||
return ActionHelper(new kiwano::ActionDelay(delay));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画组合
|
/// @brief 动画组合
|
||||||
/// @param actions 动画集合
|
/// @param actions 动画集合
|
||||||
/// @param sequence 动画按顺序依次执行或同时执行
|
/// @param sequence 动画按顺序依次执行或同时执行
|
||||||
static inline ActionHelper
|
static inline ActionHelper Group(Vector<ActionPtr> const& actions, bool sequence = true)
|
||||||
Group(Vector<ActionPtr> const& actions, bool sequence = true)
|
{
|
||||||
{
|
return ActionHelper(new kiwano::ActionGroup(actions, sequence));
|
||||||
return ActionHelper(new kiwano::ActionGroup(actions, sequence));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 同步动画组合
|
/// @brief 同步动画组合
|
||||||
/// @param actions 动画集合
|
/// @param actions 动画集合
|
||||||
static inline ActionHelper
|
static inline ActionHelper Multiple(Vector<ActionPtr> const& actions)
|
||||||
Multiple(Vector<ActionPtr> const& actions)
|
{
|
||||||
{
|
return ActionHelper(new kiwano::ActionGroup(actions, false));
|
||||||
return ActionHelper(new kiwano::ActionGroup(actions, false));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -18,93 +18,93 @@
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include <kiwano/2d/action/ActionManager.h>
|
|
||||||
#include <kiwano/2d/Actor.h>
|
#include <kiwano/2d/Actor.h>
|
||||||
|
#include <kiwano/2d/action/ActionManager.h>
|
||||||
#include <kiwano/core/Logger.h>
|
#include <kiwano/core/Logger.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
void ActionManager::UpdateActions(Actor* target, Duration dt)
|
void ActionManager::UpdateActions(Actor* target, Duration dt)
|
||||||
{
|
{
|
||||||
if (actions_.empty() || !target)
|
if (actions_.empty() || !target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ActionPtr next;
|
ActionPtr next;
|
||||||
for (auto action = actions_.first_item(); action; action = next)
|
for (auto action = actions_.first_item(); action; action = next)
|
||||||
{
|
{
|
||||||
next = action->next_item();
|
next = action->next_item();
|
||||||
|
|
||||||
if (action->IsRunning())
|
if (action->IsRunning())
|
||||||
action->UpdateStep(target, dt);
|
action->UpdateStep(target, dt);
|
||||||
|
|
||||||
if (action->IsRemoveable())
|
if (action->IsRemoveable())
|
||||||
actions_.remove(action);
|
actions_.remove(action);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Action* ActionManager::AddAction(ActionPtr action)
|
|
||||||
{
|
|
||||||
return AddAction(action.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Action* ActionManager::AddAction(Action* action)
|
|
||||||
{
|
|
||||||
KGE_ASSERT(action && "AddAction failed, NULL pointer exception");
|
|
||||||
|
|
||||||
if (action)
|
|
||||||
{
|
|
||||||
actions_.push_back(action);
|
|
||||||
}
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionPtr ActionManager::GetAction(String const & name)
|
|
||||||
{
|
|
||||||
if (actions_.empty())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
for (auto& action : actions_)
|
|
||||||
if (action->IsName(name))
|
|
||||||
return action;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionManager::ResumeAllActions()
|
|
||||||
{
|
|
||||||
if (actions_.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto& action : actions_)
|
|
||||||
{
|
|
||||||
action->Resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionManager::PauseAllActions()
|
|
||||||
{
|
|
||||||
if (actions_.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto& action : actions_)
|
|
||||||
{
|
|
||||||
action->Pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionManager::StopAllActions()
|
|
||||||
{
|
|
||||||
if (actions_.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto& action : actions_)
|
|
||||||
{
|
|
||||||
action->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ActionManager::Actions& ActionManager::GetAllActions() const
|
|
||||||
{
|
|
||||||
return actions_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action* ActionManager::AddAction(ActionPtr action)
|
||||||
|
{
|
||||||
|
return AddAction(action.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Action* ActionManager::AddAction(Action* action)
|
||||||
|
{
|
||||||
|
KGE_ASSERT(action && "AddAction failed, NULL pointer exception");
|
||||||
|
|
||||||
|
if (action)
|
||||||
|
{
|
||||||
|
actions_.push_back(action);
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::ResumeAllActions()
|
||||||
|
{
|
||||||
|
if (actions_.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& action : actions_)
|
||||||
|
{
|
||||||
|
action.Resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::PauseAllActions()
|
||||||
|
{
|
||||||
|
if (actions_.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& action : actions_)
|
||||||
|
{
|
||||||
|
action.Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::StopAllActions()
|
||||||
|
{
|
||||||
|
if (actions_.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto& action : actions_)
|
||||||
|
{
|
||||||
|
action.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionPtr ActionManager::GetAction(String const& name)
|
||||||
|
{
|
||||||
|
if (actions_.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (auto& action : actions_)
|
||||||
|
if (action.IsName(name))
|
||||||
|
return &action;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActionManager::Actions& ActionManager::GetAllActions() const
|
||||||
|
{
|
||||||
|
return actions_;
|
||||||
|
}
|
||||||
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -23,59 +23,59 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* \addtogroup Actions
|
* \addtogroup Actions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 动画管理器
|
* @brief 动画管理器
|
||||||
*/
|
*/
|
||||||
class KGE_API ActionManager
|
class KGE_API ActionManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 动画列表
|
/// @brief 动画列表
|
||||||
using Actions = IntrusiveList<ActionPtr>;
|
using Actions = IntrusiveList<ActionPtr>;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加动画
|
/// @brief 添加动画
|
||||||
Action* AddAction(ActionPtr action);
|
Action* AddAction(ActionPtr action);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 添加动画
|
/// @brief 添加动画
|
||||||
Action* AddAction(Action* action);
|
Action* AddAction(Action* action);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取指定名称的动画
|
/// @brief 继续所有暂停动画
|
||||||
/// @param name 动画名称
|
void ResumeAllActions();
|
||||||
ActionPtr GetAction(String const& name);
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 继续所有暂停动画
|
/// @brief 暂停所有动画
|
||||||
void ResumeAllActions();
|
void PauseAllActions();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 暂停所有动画
|
/// @brief 停止所有动画
|
||||||
void PauseAllActions();
|
void StopAllActions();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 停止所有动画
|
/// @brief 获取指定名称的动画
|
||||||
void StopAllActions();
|
/// @param name 动画名称
|
||||||
|
ActionPtr GetAction(String const& name);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 获取所有动画
|
/// @brief 获取所有动画
|
||||||
Actions const& GetAllActions() const;
|
Actions const& GetAllActions() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 更新动画
|
/// @brief 更新动画
|
||||||
void UpdateActions(Actor* target, Duration dt);
|
void UpdateActions(Actor* target, Duration dt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Actions actions_;
|
Actions actions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
} // namespace kiwano
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue