Format codes

This commit is contained in:
Nomango 2020-01-21 10:09:55 +08:00
parent 1e12296181
commit 4aa8a549aa
211 changed files with 28880 additions and 28843 deletions

108
.clang-format Normal file
View File

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

View File

@ -14,10 +14,10 @@ insert_final_newline = true
charset = gb2312
# 4 space indentation
indent_style = tab
indent_style = space
indent_size = 4
# Matches the exact files
[*.{json,xml}]
indent_style = space
indent_size = 2
indent_size = 2

View File

@ -65,13 +65,13 @@
<ClInclude Include="..\..\src\kiwano\platform\Window.h" />
<ClInclude Include="..\..\src\kiwano\render\Brush.h" />
<ClInclude Include="..\..\src\kiwano\render\Color.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\D2DDeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\D3D10DeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\D3D11DeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\FontCollectionLoader.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\helper.h" />
<ClInclude Include="..\..\src\kiwano\render\dx\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\D2DDeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" />
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\render\Font.h" />
<ClInclude Include="..\..\src\kiwano\render\Geometry.h" />
<ClInclude Include="..\..\src\kiwano\render\GeometrySink.h" />
@ -136,11 +136,11 @@
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Brush.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Color.cpp" />
<ClCompile Include="..\..\src\kiwano\render\dx\D2DDeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\dx\D3D10DeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\dx\D3D11DeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\dx\FontCollectionLoader.cpp" />
<ClCompile Include="..\..\src\kiwano\render\dx\TextRenderer.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\D2DDeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D10DeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\D3D11DeviceResources.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.cpp" />
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextRenderer.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Font.cpp" />
<ClCompile Include="..\..\src\kiwano\render\Geometry.cpp" />
<ClCompile Include="..\..\src\kiwano\render\GeometrySink.cpp" />

View File

@ -28,7 +28,7 @@
<Filter Include="render">
<UniqueIdentifier>{adb44ca9-674a-4b77-993f-d65193d8ab06}</UniqueIdentifier>
</Filter>
<Filter Include="render\dx">
<Filter Include="render\DirectX">
<UniqueIdentifier>{fd281702-0006-46d2-8fd1-28c502464164}</UniqueIdentifier>
</Filter>
</ItemGroup>
@ -222,27 +222,6 @@
<ClInclude Include="..\..\src\kiwano\core\Time.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\D2DDeviceResources.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\D3D10DeviceResources.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\D3D11DeviceResources.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\D3DDeviceResourcesBase.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\FontCollectionLoader.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\helper.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\dx\TextRenderer.h">
<Filter>render\dx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\render\Brush.h">
<Filter>render</Filter>
</ClInclude>
@ -285,6 +264,27 @@
<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>
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
@ -431,21 +431,6 @@
<ClCompile Include="..\..\src\kiwano\core\Time.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\dx\D2DDeviceResources.cpp">
<Filter>render\dx</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\dx\D3D10DeviceResources.cpp">
<Filter>render\dx</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\dx\D3D11DeviceResources.cpp">
<Filter>render\dx</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\dx\FontCollectionLoader.cpp">
<Filter>render\dx</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\dx\TextRenderer.cpp">
<Filter>render\dx</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\render\Brush.cpp">
<Filter>render</Filter>
</ClCompile>
@ -485,5 +470,20 @@
<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>
</Project>

84
scripts/clang-format-all Normal file
View File

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

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -19,64 +19,66 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-audio/Sound.h>
#include <kiwano-audio/Transcoder.h>
#include <kiwano/core/Common.h>
#include <kiwano/core/Component.h>
#include <kiwano-audio/Transcoder.h>
#include <kiwano-audio/Sound.h>
#include <xaudio2.h>
namespace kiwano
{
namespace audio
{
/**
* \~chinese
* \defgroup Audio
*/
namespace audio
{
/**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* \defgroup Audio
*/
/**
* \~chinese
* @brief
*/
class KGE_API AudioEngine
: public Singleton<AudioEngine>
, public ComponentBase
{
friend Singleton<AudioEngine>;
/**
* \addtogroup Audio
* @{
*/
public:
/// \~chinese
/// @brief 开启音频设备
void Open();
/**
* \~chinese
* @brief
*/
class KGE_API AudioEngine
: public Singleton<AudioEngine>
, public ComponentBase
{
friend Singleton<AudioEngine>;
/// \~chinese
/// @brief 关闭音频设备
void Close();
public:
/// \~chinese
/// @brief 开启音频设备
void Open();
/// \~chinese
/// @brief 从解码器数据缓冲中创建音频对象
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
/// \~chinese
/// @brief 关闭音频设备
void Close();
public:
void SetupComponent() override;
/// \~chinese
/// @brief 从解码器数据缓冲中创建音频对象
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
void DestroyComponent() override;
public:
void SetupComponent() override;
private:
AudioEngine();
void DestroyComponent() override;
~AudioEngine();
private:
AudioEngine();
private:
IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;
};
~AudioEngine();
/** @} */
}
}
private:
IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;
};
/** @} */
} // namespace audio
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,210 +18,210 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano-audio/AudioEngine.h>
#include <kiwano-audio/Sound.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/FileSystem.h>
#include <kiwano-audio/Sound.h>
#include <kiwano-audio/AudioEngine.h>
namespace kiwano
{
namespace audio
{
namespace audio
{
Sound::Sound()
: opened_(false)
, playing_(false)
, 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()
: opened_(false)
, playing_(false)
, 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);
}
} // namespace audio
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,110 +19,108 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-audio/Transcoder.h>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/Resource.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <kiwano-audio/Transcoder.h>
#include <xaudio2.h>
namespace kiwano
{
namespace audio
{
class AudioEngine;
namespace audio
{
class AudioEngine;
KGE_DECLARE_SMART_PTR(Sound);
KGE_DECLARE_SMART_PTR(Sound);
/**
* \addtogroup Audio
* @{
*/
/**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Sound
: public virtual ObjectBase
{
friend class AudioEngine;
/**
* \~chinese
* @brief
*/
class KGE_API Sound : public virtual ObjectBase
{
friend class AudioEngine;
public:
Sound();
public:
Sound();
virtual ~Sound();
virtual ~Sound();
/// \~chinese
/// @brief 打开本地音频文件
/// @param res 本地音频文件路径
bool Load(String const& file_path);
/// \~chinese
/// @brief 打开本地音频文件
/// @param res 本地音频文件路径
bool Load(String const& file_path);
/// \~chinese
/// @brief 打开音频资源
/// @param res 音频资源
bool Load(Resource const& res);
/// \~chinese
/// @brief 打开音频资源
/// @param res 音频资源
bool Load(Resource const& res);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 播放
/// @param loop_count 播放循环次数,设置 -1 为循环播放
void Play(int loop_count = 0);
/// \~chinese
/// @brief 播放
/// @param loop_count 播放循环次数,设置 -1 为循环播放
void Play(int loop_count = 0);
/// \~chinese
/// @brief 暂停
void Pause();
/// \~chinese
/// @brief 暂停
void Pause();
/// \~chinese
/// @brief 继续
void Resume();
/// \~chinese
/// @brief 继续
void Resume();
/// \~chinese
/// @brief 停止
void Stop();
/// \~chinese
/// @brief 停止
void Stop();
/// \~chinese
/// @brief 关闭并销毁资源
void Close();
/// \~chinese
/// @brief 关闭并销毁资源
void Close();
/// \~chinese
/// @brief 是否正在播放
bool IsPlaying() const;
/// \~chinese
/// @brief 是否正在播放
bool IsPlaying() const;
/// \~chinese
/// @brief 获取音量
float GetVolume() const;
/// \~chinese
/// @brief 获取音量
float GetVolume() const;
/// \~chinese
/// @brief 设置音量
/// @param volume 音量大小1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
void SetVolume(float volume);
/// \~chinese
/// @brief 设置音量
/// @param volume 音量大小1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
void SetVolume(float volume);
private:
IXAudio2SourceVoice* GetXAudio2Voice() const;
private:
IXAudio2SourceVoice* GetXAudio2Voice() const;
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
private:
bool opened_;
bool playing_;
Transcoder transcoder_;
IXAudio2SourceVoice* voice_;
};
private:
bool opened_;
bool playing_;
Transcoder transcoder_;
IXAudio2SourceVoice* voice_;
};
/** @} */
/** @} */
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
{
return voice_;
}
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
{
voice_ = voice;
}
}
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
{
return voice_;
}
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
{
voice_ = voice;
}
} // namespace audio
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -22,135 +22,135 @@
namespace kiwano
{
namespace audio
{
SoundPlayer::SoundPlayer()
: 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();
}
}
namespace audio
{
SoundPlayer::SoundPlayer()
: 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();
}
} // namespace audio
} // namespace kiwano

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -19,280 +19,252 @@
// THE SOFTWARE.
#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
#include <kiwano/macros.h>
#include <kiwano-audio/Transcoder.h>
#include <kiwano-audio/libraries.h>
#include <kiwano/core/Common.h>
#include <kiwano/core/Resource.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/libraries.h>
#include <kiwano-audio/libraries.h>
#include <kiwano-audio/Transcoder.h>
namespace kiwano
{
namespace audio
{
namespace audio
{
Transcoder::Transcoder()
: wave_format_(nullptr)
, wave_data_(nullptr)
, 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()
: wave_format_(nullptr)
, wave_data_(nullptr)
, 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;
}
} // namespace audio
} // namespace kiwano

View File

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

View File

@ -1,15 +1,15 @@
// 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

View File

@ -1,15 +1,15 @@
// 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
@ -18,81 +18,84 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <kiwano-audio/libraries.h>
#include <kiwano/core/Logger.h>
namespace kiwano
{
namespace audio
{
namespace dlls
{
XAudio2::XAudio2()
: xaudio2()
, XAudio2Create(nullptr)
{
const auto xaudio2_dll_names =
{
"xaudio2_9.dll", // for Windows 10
"xaudio2_8.dll", // for Windows 8
"xaudio2_7.dll" // for DirectX SDK
};
namespace audio
{
namespace dlls
{
XAudio2::XAudio2()
: xaudio2()
, XAudio2Create(nullptr)
{
const auto xaudio2_dll_names = {
"xaudio2_9.dll", // for Windows 10
"xaudio2_8.dll", // for Windows 8
"xaudio2_7.dll" // for DirectX SDK
};
for (const auto& name : xaudio2_dll_names)
{
if (xaudio2.Load(name))
{
break;
}
}
for (const auto& name : xaudio2_dll_names)
{
if (xaudio2.Load(name))
{
break;
}
}
if (xaudio2.IsValid())
{
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("XAudio2Create");
}
else
{
KGE_ERROR(L"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");
}
}
}
}
if (xaudio2.IsValid())
{
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("XAudio2Create");
}
else
{
KGE_ERROR(L"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");
}
}
} // namespace dlls
} // namespace audio
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -20,80 +20,79 @@
#pragma once
#include <kiwano/core/Library.h>
#include <xaudio2.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <xaudio2.h>
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
namespace kiwano
{
namespace audio
{
namespace dlls
{
class KGE_API XAudio2
{
public:
static inline XAudio2& Get()
{
static XAudio2 instance;
return instance;
}
namespace audio
{
namespace dlls
{
class KGE_API XAudio2
{
public:
static inline XAudio2& Get()
{
static XAudio2 instance;
return instance;
}
// XAudio2 functions
typedef HRESULT(WINAPI* PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
// XAudio2 functions
typedef HRESULT(WINAPI* PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
PFN_XAudio2Create XAudio2Create;
PFN_XAudio2Create XAudio2Create;
private:
XAudio2();
private:
XAudio2();
XAudio2(const XAudio2&) = delete;
XAudio2& operator=(const XAudio2&) = delete;
XAudio2(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
{
public:
static inline MediaFoundation& Get()
{
static MediaFoundation instance;
return instance;
}
// MediaFoundation functions
typedef HRESULT(WINAPI* PFN_MFStartup)(ULONG, DWORD);
typedef HRESULT(WINAPI* PFN_MFShutdown)();
typedef HRESULT(WINAPI* PFN_MFCreateMediaType)(IMFMediaType**);
typedef HRESULT(WINAPI* PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI* PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
// MediaFoundation functions
typedef HRESULT(WINAPI* PFN_MFStartup)(ULONG, DWORD);
typedef HRESULT(WINAPI* PFN_MFShutdown)();
typedef HRESULT(WINAPI* PFN_MFCreateMediaType)(IMFMediaType**);
typedef HRESULT(WINAPI* PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI* PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI* PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
PFN_MFStartup MFStartup;
PFN_MFShutdown MFShutdown;
PFN_MFCreateMediaType MFCreateMediaType;
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
PFN_MFStartup MFStartup;
PFN_MFShutdown MFShutdown;
PFN_MFCreateMediaType MFCreateMediaType;
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
private:
MediaFoundation();
private:
MediaFoundation();
MediaFoundation(const MediaFoundation&) = delete;
MediaFoundation& operator=(const MediaFoundation&) = delete;
MediaFoundation(const MediaFoundation&) = delete;
MediaFoundation& operator=(const MediaFoundation&) = delete;
Library mfplat;
Library mfreadwrite;
};
}
}
}
Library mfplat;
Library mfreadwrite;
};
} // namespace dlls
} // namespace audio
} // namespace kiwano
#endif

View File

@ -1,15 +1,15 @@
// 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
@ -22,47 +22,45 @@
namespace kiwano
{
namespace imgui
{
ImGuiLayer::ImGuiLayer()
{
SetSwallowEvents(true);
}
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
{
ImGuiLayer::ImGuiLayer()
{
SetSwallowEvents(true);
}
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

View File

@ -1,15 +1,15 @@
// 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
@ -23,49 +23,48 @@
namespace kiwano
{
namespace imgui
{
KGE_DECLARE_SMART_PTR(ImGuiLayer);
namespace imgui
{
KGE_DECLARE_SMART_PTR(ImGuiLayer);
/// \~chinese
/// @brief ImGui管道
using ImGuiPipeline = Function<void()>;
/// \~chinese
/// @brief ImGui管道
using ImGuiPipeline = Function<void()>;
/**
* \~chinese
* @brief ImGui图层
*/
class ImGuiLayer
: public Layer
{
public:
ImGuiLayer();
/**
* \~chinese
* @brief ImGui图层
*/
class ImGuiLayer : public Layer
{
public:
ImGuiLayer();
virtual ~ImGuiLayer();
virtual ~ImGuiLayer();
/// \~chinese
/// @brief 添加 ImGui 元素
/// @param name 元素名称
/// @param item 管道
void AddItem(String const& name, ImGuiPipeline const& item);
/// \~chinese
/// @brief 添加 ImGui 元素
/// @param name 元素名称
/// @param item 管道
void AddItem(String const& name, ImGuiPipeline const& item);
/// \~chinese
/// @brief 移除 ImGui 元素
/// @param name 元素名称
void RemoveItem(String const& name);
/// \~chinese
/// @brief 移除 ImGui 元素
/// @param name 元素名称
void RemoveItem(String const& name);
// 移除所有元素
/// \~chinese
/// @brief 移除所有元素
void RemoveAllItems();
// 移除所有元素
/// \~chinese
/// @brief 移除所有元素
void RemoveAllItems();
public:
void OnRender(RenderContext& ctx) override;
public:
void OnRender(RenderContext& ctx) override;
bool CheckVisibility(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
Map<String, ImGuiPipeline> pipelines_;
};
}
}
private:
Map<String, ImGuiPipeline> pipelines_;
};
} // namespace imgui
} // namespace kiwano

View File

@ -1,209 +1,235 @@
// Copyright (C) 2019 Nomango
#include <kiwano-imgui/ImGuiModule.h>
#include <kiwano-imgui/imgui_impl.h>
#include <kiwano/core/Common.h>
#include <kiwano/core/event/KeyEvent.h>
#include <kiwano/core/event/MouseEvent.h>
#include <kiwano/platform/Window.h>
#include <kiwano/platform/Input.h>
#include <kiwano/platform/Window.h>
#include <kiwano/render/Renderer.h>
#include <kiwano-imgui/ImGuiModule.h>
#include <kiwano-imgui/imgui_impl.h>
namespace kiwano
{
namespace imgui
{
ImGuiModule::ImGuiModule()
: target_window_(nullptr)
{
}
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
{
ImGuiModule::ImGuiModule()
: target_window_(nullptr)
{
}
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

View File

@ -1,15 +1,15 @@
// 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
@ -24,46 +24,46 @@
namespace kiwano
{
namespace imgui
{
/**
* \~chinese
* @brief ImGuiÄ£¿é
*/
class ImGuiModule
: public Singleton<ImGuiModule>
, public RenderComponent
, public UpdateComponent
, public EventComponent
{
friend Singleton<ImGuiModule>;
namespace imgui
{
/**
* \~chinese
* @brief ImGuiÄ£¿é
*/
class ImGuiModule
: public Singleton<ImGuiModule>
, public RenderComponent
, public UpdateComponent
, public EventComponent
{
friend Singleton<ImGuiModule>;
public:
ImGuiModule();
public:
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 HandleEvent(Event* evt) override;
void HandleEvent(Event* evt) override;
void OnUpdate(Duration dt) override;
void OnUpdate(Duration dt) override;
private:
void NewFrame();
private:
void NewFrame();
void Render();
void Render();
void UpdateMousePos();
void UpdateMousePos();
void UpdateMouseCursor();
void UpdateMouseCursor();
private:
WindowHandle target_window_;
};
}
}
private:
WindowHandle target_window_;
};
} // namespace imgui
} // namespace kiwano

View File

@ -8,25 +8,62 @@
#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 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 bool ImGui_Impl_Init(::kiwano::Renderer& renderer)
{
return ImGui_ImplDX11_Init(renderer.GetD3DDeviceResources()->GetDevice(),
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 bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX11_CreateDeviceObjects(); }
inline void ImGui_Impl_InvalidateDeviceObjects()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
}
inline bool ImGui_Impl_CreateDeviceObjects()
{
return ImGui_ImplDX11_CreateDeviceObjects();
}
#else
#include <kiwano-imgui/imgui_impl_dx10.h>
inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer) { return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice()); }
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 bool ImGui_Impl_Init(::kiwano::Renderer& renderer)
{
return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice());
}
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 bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX10_CreateDeviceObjects(); }
inline void ImGui_Impl_InvalidateDeviceObjects()
{
ImGui_ImplDX10_InvalidateDeviceObjects();
}
inline bool ImGui_Impl_CreateDeviceObjects()
{
return ImGui_ImplDX10_CreateDeviceObjects();
}
#endif

View File

@ -3,40 +3,41 @@
#include <kiwano-imgui/imgui_impl_dx10.h>
// DirectX
#include <stdio.h>
#include <d3d10_1.h>
#include <d3d10.h>
#include <d3d10_1.h>
#include <d3dcompiler.h>
#include <stdio.h>
#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
// DirectX data
static ID3D10Device* g_pd3dDevice = NULL;
static IDXGIFactory* g_pFactory = NULL;
static ID3D10Buffer* g_pVB = NULL;
static ID3D10Buffer* g_pIB = NULL;
static ID3D10Blob* g_pVertexShaderBlob = NULL;
static ID3D10VertexShader* g_pVertexShader = NULL;
static ID3D10InputLayout* g_pInputLayout = NULL;
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10Blob* g_pPixelShaderBlob = NULL;
static ID3D10PixelShader* g_pPixelShader = NULL;
static ID3D10SamplerState* g_pFontSampler = NULL;
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
static ID3D10RasterizerState* g_pRasterizerState = NULL;
static ID3D10BlendState* g_pBlendState = NULL;
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
static ID3D10Device* g_pd3dDevice = NULL;
static IDXGIFactory* g_pFactory = NULL;
static ID3D10Buffer* g_pVB = NULL;
static ID3D10Buffer* g_pIB = NULL;
static ID3D10Blob* g_pVertexShaderBlob = NULL;
static ID3D10VertexShader* g_pVertexShader = NULL;
static ID3D10InputLayout* g_pInputLayout = NULL;
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10Blob* g_pPixelShaderBlob = NULL;
static ID3D10PixelShader* g_pPixelShader = NULL;
static ID3D10SamplerState* g_pFontSampler = NULL;
static ID3D10ShaderResourceView* g_pFontTextureView = NULL;
static ID3D10RasterizerState* g_pRasterizerState = NULL;
static ID3D10BlendState* g_pBlendState = NULL;
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
float mvp[4][4];
};
// 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)
{
ID3D10Device* ctx = g_pd3dDevice;
@ -44,28 +45,36 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
// Create and grow vertex/index buffers if needed
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;
D3D10_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.MiscFlags = 0;
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
return;
}
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;
D3D10_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
return;
@ -73,7 +82,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
// Copy and convert all vertices into a single contiguous buffer
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
for (int n = 0; n < draw_data->CmdListsCount; n++)
@ -88,48 +97,49 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
g_pIB->Unmap();
// 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;
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] = {
{ 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
};
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
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
{
UINT ScissorRectsCount, ViewportsCount;
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D10RasterizerState* RS;
ID3D10BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D10DepthStencilState* DepthStencilState;
ID3D10ShaderResourceView* PSShaderResource;
ID3D10SamplerState* PSSampler;
ID3D10PixelShader* PS;
ID3D10VertexShader* VS;
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D10InputLayout* InputLayout;
UINT ScissorRectsCount, ViewportsCount;
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D10RasterizerState* RS;
ID3D10BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D10DepthStencilState* DepthStencilState;
ID3D10ShaderResourceView* PSShaderResource;
ID3D10SamplerState* PSSampler;
ID3D10PixelShader* PS;
ID3D10VertexShader* VS;
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D10Buffer * IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D10InputLayout* InputLayout;
};
BACKUP_DX10_STATE old;
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
D3D10_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
vp.Width = (UINT)draw_data->DisplaySize.x;
vp.Height = (UINT)draw_data->DisplaySize.y;
vp.Width = (UINT)draw_data->DisplaySize.x;
vp.Height = (UINT)draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
@ -177,9 +187,9 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
ctx->RSSetState(g_pRasterizerState);
// Render command lists
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 pos = draw_data->DisplayPos;
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
@ -194,7 +204,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
else
{
// 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);
// Bind texture, Draw
@ -210,55 +221,77 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); 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->RSSetState(old.RS);
if (old.RS)
old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask);
if (old.BlendState)
old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef);
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->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) 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();
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset);
if (old.IndexBuffer)
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()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D10_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D10Texture2D *pTexture = NULL;
ID3D10Texture2D* pTexture = NULL;
D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
ZeroMemory(&srv_desc, sizeof(srv_desc));
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = desc.MipLevels;
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = desc.MipLevels;
srv_desc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
pTexture->Release();
@ -271,35 +304,36 @@ static void ImGui_ImplDX10_CreateFontsTexture()
{
D3D10_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
}
}
bool ImGui_ImplDX10_CreateDeviceObjects()
bool ImGui_ImplDX10_CreateDeviceObjects()
{
if (!g_pd3dDevice)
return false;
if (g_pFontSampler)
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)
// If you would like to use this DX10 sample code but remove this dependency you can:
// 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.
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of
// d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) If you would like to use this DX10 sample code but remove this
// dependency you can:
// 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.
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
static const char* vertexShader = "cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
@ -326,38 +360,46 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
return output;\
}";
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, 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!
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob,
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;
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;
// Create the input layout
D3D10_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
D3D10_INPUT_ELEMENT_DESC local_layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA,
0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA,
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;
// Create the constant buffer
{
D3D10_BUFFER_DESC desc;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.MiscFlags = 0;
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
}
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
static const char* pixelShader = "struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
@ -372,10 +414,15 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
return out_col; \
}";
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, 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!
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob,
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;
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;
}
@ -383,14 +430,14 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
{
D3D10_BLEND_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AlphaToCoverageEnable = false;
desc.BlendEnable[0] = true;
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
desc.BlendOp = D3D10_BLEND_OP_ADD;
desc.SrcBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
desc.DestBlendAlpha = D3D10_BLEND_ZERO;
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
desc.AlphaToCoverageEnable = false;
desc.BlendEnable[0] = true;
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
desc.BlendOp = D3D10_BLEND_OP_ADD;
desc.SrcBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
desc.DestBlendAlpha = D3D10_BLEND_ZERO;
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
}
@ -399,9 +446,9 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
{
D3D10_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D10_FILL_SOLID;
desc.CullMode = D3D10_CULL_NONE;
desc.ScissorEnable = true;
desc.FillMode = D3D10_FILL_SOLID;
desc.CullMode = D3D10_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
}
@ -410,13 +457,14 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
{
D3D10_DEPTH_STENCIL_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.DepthEnable = false;
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
desc.DepthEnable = false;
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp =
D3D10_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
desc.BackFace = desc.FrontFace;
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
}
@ -425,46 +473,101 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
return true;
}
void ImGui_ImplDX10_InvalidateDeviceObjects()
void ImGui_ImplDX10_InvalidateDeviceObjects()
{
if (!g_pd3dDevice)
return;
if (g_pFontSampler) { g_pFontSampler->Release(); 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_pFontSampler)
{
g_pFontSampler->Release();
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_pDepthStencilState) { g_pDepthStencilState->Release(); 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; }
if (g_pBlendState)
{
g_pBlendState->Release();
g_pBlendState = NULL;
}
if (g_pDepthStencilState)
{
g_pDepthStencilState->Release();
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";
// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
IDXGIDevice* pDXGIDevice = NULL;
IDXGIAdapter* pDXGIAdapter = NULL;
IDXGIFactory* pFactory = NULL;
IDXGIFactory* pFactory = NULL;
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
{
g_pd3dDevice = device;
g_pFactory = pFactory;
g_pFactory = pFactory;
}
if (pDXGIDevice) pDXGIDevice->Release();
if (pDXGIAdapter) pDXGIAdapter->Release();
if (pDXGIDevice)
pDXGIDevice->Release();
if (pDXGIAdapter)
pDXGIAdapter->Release();
return true;
}
@ -472,7 +575,11 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
void ImGui_ImplDX10_Shutdown()
{
ImGui_ImplDX10_InvalidateDeviceObjects();
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
if (g_pFactory)
{
g_pFactory->Release();
g_pFactory = NULL;
}
g_pd3dDevice = NULL;
}

View File

@ -7,13 +7,13 @@
struct ID3D10Device;
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
#endif

View File

@ -3,40 +3,41 @@
#include <kiwano-imgui/imgui_impl_dx11.h>
// DirectX
#include <stdio.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <stdio.h>
#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
// DirectX data
static ID3D11Device* g_pd3dDevice = NULL;
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
static IDXGIFactory* g_pFactory = NULL;
static ID3D11Buffer* g_pVB = NULL;
static ID3D11Buffer* g_pIB = NULL;
static ID3D10Blob* g_pVertexShaderBlob = NULL;
static ID3D11VertexShader* g_pVertexShader = NULL;
static ID3D11InputLayout* g_pInputLayout = NULL;
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10Blob* g_pPixelShaderBlob = NULL;
static ID3D11PixelShader* g_pPixelShader = NULL;
static ID3D11SamplerState* g_pFontSampler = NULL;
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
static ID3D11RasterizerState* g_pRasterizerState = NULL;
static ID3D11BlendState* g_pBlendState = NULL;
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
static ID3D11Device* g_pd3dDevice = NULL;
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
static IDXGIFactory* g_pFactory = NULL;
static ID3D11Buffer* g_pVB = NULL;
static ID3D11Buffer* g_pIB = NULL;
static ID3D10Blob* g_pVertexShaderBlob = NULL;
static ID3D11VertexShader* g_pVertexShader = NULL;
static ID3D11InputLayout* g_pInputLayout = NULL;
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
static ID3D10Blob* g_pPixelShaderBlob = NULL;
static ID3D11PixelShader* g_pPixelShader = NULL;
static ID3D11SamplerState* g_pFontSampler = NULL;
static ID3D11ShaderResourceView* g_pFontTextureView = NULL;
static ID3D11RasterizerState* g_pRasterizerState = NULL;
static ID3D11BlendState* g_pBlendState = NULL;
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
float mvp[4][4];
};
// 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)
{
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
@ -44,27 +45,35 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
// Create and grow vertex/index buffers if needed
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;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.MiscFlags = 0;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
return;
}
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;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
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)
return;
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++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
@ -90,50 +99,51 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
ctx->Unmap(g_pIB, 0);
// 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;
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] = {
{ 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
};
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
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
{
UINT ScissorRectsCount, ViewportsCount;
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D11RasterizerState* RS;
ID3D11BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D11DepthStencilState* DepthStencilState;
ID3D11ShaderResourceView* PSShaderResource;
ID3D11SamplerState* PSSampler;
ID3D11PixelShader* PS;
ID3D11VertexShader* VS;
UINT PSInstancesCount, VSInstancesCount;
ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D11InputLayout* InputLayout;
UINT ScissorRectsCount, ViewportsCount;
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D11RasterizerState* RS;
ID3D11BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D11DepthStencilState* DepthStencilState;
ID3D11ShaderResourceView* PSShaderResource;
ID3D11SamplerState* PSSampler;
ID3D11PixelShader* PS;
ID3D11VertexShader* VS;
UINT PSInstancesCount, VSInstancesCount;
ID3D11ClassInstance *PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D11Buffer * IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D11InputLayout* InputLayout;
};
BACKUP_DX11_STATE old;
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
D3D11_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
vp.Width = draw_data->DisplaySize.x;
vp.Height = draw_data->DisplaySize.y;
vp.Width = draw_data->DisplaySize.x;
vp.Height = draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
@ -182,9 +192,9 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
ctx->RSSetState(g_pRasterizerState);
// Render command lists
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 pos = draw_data->DisplayPos;
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
@ -199,7 +209,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
else
{
// 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);
// Bind texture, Draw
@ -215,61 +226,87 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); 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, 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->RSSetState(old.RS);
if (old.RS)
old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask);
if (old.BlendState)
old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef);
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, 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->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) 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();
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset);
if (old.IndexBuffer)
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()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D11Texture2D *pTexture = NULL;
ID3D11Texture2D* pTexture = NULL;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
if (pTexture)
{
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
pTexture->Release();
}
@ -282,35 +319,36 @@ static void ImGui_ImplDX11_CreateFontsTexture()
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
}
}
bool ImGui_ImplDX11_CreateDeviceObjects()
bool ImGui_ImplDX11_CreateDeviceObjects()
{
if (!g_pd3dDevice)
return false;
if (g_pFontSampler)
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)
// If you would like to use this DX11 sample code but remove this dependency you can:
// 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.
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of
// d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) If you would like to use this DX11 sample code but remove this
// dependency you can:
// 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.
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
static const char* vertexShader = "cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
@ -337,38 +375,46 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
return output;\
}";
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, 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!
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob,
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;
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;
// Create the input layout
D3D11_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
D3D11_INPUT_ELEMENT_DESC local_layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA,
0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA,
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;
// Create the constant buffer
{
D3D11_BUFFER_DESC desc;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.MiscFlags = 0;
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
}
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
static const char* pixelShader = "struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
@ -383,10 +429,15 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
return out_col; \
}";
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, 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!
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob,
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;
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;
}
@ -394,14 +445,14 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
{
D3D11_BLEND_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AlphaToCoverageEnable = false;
desc.RenderTarget[0].BlendEnable = true;
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.AlphaToCoverageEnable = false;
desc.RenderTarget[0].BlendEnable = true;
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
}
@ -410,9 +461,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
{
D3D11_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
desc.ScissorEnable = true;
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
}
@ -421,13 +472,14 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
{
D3D11_DEPTH_STENCIL_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.DepthEnable = false;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.DepthEnable = false;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp =
D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
desc.BackFace = desc.FrontFace;
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
}
@ -436,47 +488,102 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
return true;
}
void ImGui_ImplDX11_InvalidateDeviceObjects()
void ImGui_ImplDX11_InvalidateDeviceObjects()
{
if (!g_pd3dDevice)
return;
if (g_pFontSampler) { g_pFontSampler->Release(); 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_pFontSampler)
{
g_pFontSampler->Release();
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_pDepthStencilState) { g_pDepthStencilState->Release(); 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; }
if (g_pBlendState)
{
g_pBlendState->Release();
g_pBlendState = NULL;
}
if (g_pDepthStencilState)
{
g_pDepthStencilState->Release();
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";
// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
IDXGIDevice* pDXGIDevice = NULL;
IDXGIAdapter* pDXGIAdapter = NULL;
IDXGIFactory* pFactory = NULL;
IDXGIFactory* pFactory = NULL;
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
{
g_pd3dDevice = device;
g_pd3dDevice = device;
g_pd3dDeviceContext = device_context;
g_pFactory = pFactory;
g_pFactory = pFactory;
}
if (pDXGIDevice) pDXGIDevice->Release();
if (pDXGIAdapter) pDXGIAdapter->Release();
if (pDXGIDevice)
pDXGIDevice->Release();
if (pDXGIAdapter)
pDXGIAdapter->Release();
return true;
}
@ -484,8 +591,12 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
void ImGui_ImplDX11_Shutdown()
{
ImGui_ImplDX11_InvalidateDeviceObjects();
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
g_pd3dDevice = NULL;
if (g_pFactory)
{
g_pFactory->Release();
g_pFactory = NULL;
}
g_pd3dDevice = NULL;
g_pd3dDeviceContext = NULL;
}

View File

@ -8,13 +8,13 @@
struct ID3D11Device;
struct ID3D11DeviceContext;
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_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
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_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
#endif

View File

@ -1,15 +1,15 @@
// 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

View File

@ -1,15 +1,15 @@
// 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
@ -18,364 +18,338 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <thread>
#include <3rd-party/curl/curl.h> // CURL
#include <codecvt>
#include <kiwano-network/HttpClient.h>
#include <kiwano-network/HttpRequest.h>
#include <kiwano-network/HttpResponse.hpp>
#include <kiwano-network/HttpClient.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/Application.h>
#include <3rd-party/curl/curl.h> // CURL
#include <thread>
namespace
{
using namespace kiwano;
using namespace kiwano::network;
using namespace kiwano;
using namespace kiwano::network;
uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp)
{
ByteString* recv_buffer = (ByteString*)userp;
uint32_t total = size * nmemb;
uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp)
{
ByteString* recv_buffer = (ByteString*)userp;
uint32_t total = size * nmemb;
// add data to the end of recv_buffer
// write data maybe called more than once in a single request
recv_buffer->append((char*)buffer, total);
// add data to the end of recv_buffer
// write data maybe called more than once in a single request
recv_buffer->append((char*)buffer, 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_;
};
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_;
};
} // namespace
namespace kiwano
{
namespace network
{
HttpClient::HttpClient()
: timeout_for_connect_(30000 /* 30 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());
}
}
}
}
namespace network
{
HttpClient::HttpClient()
: timeout_for_connect_(30000 /* 30 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());
}
}
}
} // namespace network
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,127 +19,126 @@
// THE SOFTWARE.
#pragma once
#include <condition_variable>
#include <kiwano/core/Common.h>
#include <kiwano/core/Component.h>
#include <mutex>
#include <condition_variable>
namespace kiwano
{
namespace network
{
/**
* \~chinese
* \defgroup Network
*/
namespace network
{
/**
* \~chinese
* \defgroup Network
*/
/**
* \addtogroup Network
* @{
*/
/**
* \addtogroup Network
* @{
*/
/**
* \~chinese
* @brief HTTP客户端
*/
class KGE_API HttpClient
: public Singleton<HttpClient>
, public ComponentBase
{
friend Singleton<HttpClient>;
/**
* \~chinese
* @brief HTTP客户端
*/
class KGE_API HttpClient
: public Singleton<HttpClient>
, public ComponentBase
{
friend Singleton<HttpClient>;
public:
/// \~chinese
/// @brief 发送HTTP请求
/// @param[in] request HTTP请求
/// @details 发送请求后,无论结束或失败都将调用请求的响应回调函数
void Send(HttpRequestPtr request);
public:
/// \~chinese
/// @brief 发送HTTP请求
/// @param[in] request HTTP请求
/// @details 发送请求后,无论结束或失败都将调用请求的响应回调函数
void Send(HttpRequestPtr request);
/// \~chinese
/// @brief 设置连接超时时长
void SetTimeoutForConnect(Duration timeout);
/// \~chinese
/// @brief 设置连接超时时长
void SetTimeoutForConnect(Duration timeout);
/// \~chinese
/// @brief 获取连接超时时长
Duration GetTimeoutForConnect() const;
/// \~chinese
/// @brief 获取连接超时时长
Duration GetTimeoutForConnect() const;
/// \~chinese
/// @brief 设置读取超时时长
void SetTimeoutForRead(Duration timeout);
/// \~chinese
/// @brief 设置读取超时时长
void SetTimeoutForRead(Duration timeout);
/// \~chinese
/// @brief 获取读取超时时长
Duration GetTimeoutForRead() const;
/// \~chinese
/// @brief 获取读取超时时长
Duration GetTimeoutForRead() const;
/// \~chinese
/// @brief 设置SSL证书地址
void SetSSLVerification(String const& root_certificate_path);
/// \~chinese
/// @brief 设置SSL证书地址
void SetSSLVerification(String const& root_certificate_path);
/// \~chinese
/// @brief 获取SSL证书地址
String const& GetSSLVerification() const;
/// \~chinese
/// @brief 获取SSL证书地址
String const& GetSSLVerification() const;
public:
virtual void SetupComponent() override;
public:
virtual void SetupComponent() override;
virtual void DestroyComponent() override;
virtual void DestroyComponent() override;
private:
HttpClient();
private:
HttpClient();
void NetworkThread();
void NetworkThread();
void Perform(HttpRequestPtr request, HttpResponsePtr response);
void Perform(HttpRequestPtr request, HttpResponsePtr response);
void DispatchResponseCallback();
void DispatchResponseCallback();
private:
Duration timeout_for_connect_;
Duration timeout_for_read_;
private:
Duration timeout_for_connect_;
Duration timeout_for_read_;
String ssl_verification_;
String ssl_verification_;
std::mutex request_mutex_;
Queue<HttpRequestPtr> request_queue_;
std::mutex request_mutex_;
Queue<HttpRequestPtr> request_queue_;
std::mutex response_mutex_;
Queue<HttpResponsePtr> response_queue_;
std::mutex response_mutex_;
Queue<HttpResponsePtr> response_queue_;
std::condition_variable_any sleep_condition_;
};
std::condition_variable_any sleep_condition_;
};
/** @} */
/** @} */
inline void HttpClient::SetTimeoutForConnect(Duration 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 void HttpClient::SetTimeoutForConnect(Duration 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_;
}
} // namespace network
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -23,12 +23,12 @@
namespace kiwano
{
namespace network
{
void HttpRequest::SetJsonData(Json const& json)
{
SetHeader(L"Content-Type", L"application/json;charset=UTF-8");
data_ = json.dump();
}
}
namespace network
{
void HttpRequest::SetJsonData(Json const& json)
{
SetHeader(L"Content-Type", L"application/json;charset=UTF-8");
data_ = json.dump();
}
} // namespace network
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -25,132 +25,173 @@
namespace kiwano
{
namespace network
{
class HttpResponse;
namespace network
{
class HttpResponse;
KGE_DECLARE_SMART_PTR(HttpRequest);
KGE_DECLARE_SMART_PTR(HttpRequest);
/**
* \addtogroup Network
* @{
*/
/**
* \addtogroup Network
* @{
*/
/**
* \~chinese
* @brief HTTP请求
*/
class KGE_API HttpRequest
: public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 响应回调函数
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
/**
* \~chinese
* @brief HTTP请求
*/
class KGE_API HttpRequest : public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 响应回调函数
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
/// \~chinese
/// @brief 请求类型
enum class Type
{
Unknown, ///< 未知
Get, ///< HTTP GET请求
Post, ///< HTTP POST请求
Put, ///< HTTP PUT请求
Delete ///< HTTP DELETE请求
};
/// \~chinese
/// @brief 请求类型
enum class Type
{
Unknown, ///< 未知
Get, ///< HTTP GET请求
Post, ///< HTTP POST请求
Put, ///< HTTP PUT请求
Delete ///< HTTP DELETE请求
};
HttpRequest();
HttpRequest();
HttpRequest(Type type);
HttpRequest(Type type);
/// \~chinese
/// @brief 设置请求地址
void SetUrl(String const& url);
/// \~chinese
/// @brief 设置请求地址
void SetUrl(String const& url);
/// \~chinese
/// @brief 设置请求类型
void SetType(Type type);
/// \~chinese
/// @brief 设置请求类型
void SetType(Type type);
/// \~chinese
/// @brief 设置请求携带的数据
void SetData(String const& data);
/// \~chinese
/// @brief 设置请求携带的数据
void SetData(String const& data);
/// \~chinese
/// @brief 设置请求携带的JSON数据
void SetJsonData(Json const& json);
/// \~chinese
/// @brief 设置请求携带的JSON数据
void SetJsonData(Json const& json);
/// \~chinese
/// @brief 设置HTTP头
void SetHeaders(Map<String, String> const& headers);
/// \~chinese
/// @brief 设置HTTP头
void SetHeaders(Map<String, String> const& headers);
/// \~chinese
/// @brief 设置HTTP头
void SetHeader(String const& field, String const& content);
/// \~chinese
/// @brief 设置HTTP头
void SetHeader(String const& field, String const& content);
/// \~chinese
/// @brief 设置响应回调函数
void SetResponseCallback(ResponseCallback const& callback);
/// \~chinese
/// @brief 设置响应回调函数
void SetResponseCallback(ResponseCallback const& callback);
/// \~chinese
/// @brief 获取请求地址
String const& GetUrl() const;
/// \~chinese
/// @brief 获取请求地址
String const& GetUrl() const;
/// \~chinese
/// @brief 获取请求类型
Type GetType() const;
/// \~chinese
/// @brief 获取请求类型
Type GetType() const;
/// \~chinese
/// @brief 获取请求数据
String const& GetData() const;
/// \~chinese
/// @brief 获取请求数据
String const& GetData() const;
/// \~chinese
/// @brief 获取HTTP头
Map<String, String>& GetHeaders();
/// \~chinese
/// @brief 获取HTTP头
Map<String, String>& GetHeaders();
/// \~chinese
/// @brief 获取HTTP头
String const& GetHeader(String const& header) const;
/// \~chinese
/// @brief 获取HTTP头
String const& GetHeader(String const& header) const;
/// \~chinese
/// @brief 获取响应回调函数
ResponseCallback const& GetResponseCallback() const;
/// \~chinese
/// @brief 获取响应回调函数
ResponseCallback const& GetResponseCallback() const;
private:
Type type_;
String url_;
String data_;
Map<String, String> headers_;
ResponseCallback response_cb_;
};
private:
Type type_;
String url_;
String data_;
Map<String, String> headers_;
ResponseCallback response_cb_;
};
/** @} */
/** @} */
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::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_;
}
} // namespace network
} // namespace kiwano

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -20,6 +20,6 @@
#pragma once
#include <kiwano-network/HttpClient.h>
#include <kiwano-network/HttpRequest.h>
#include <kiwano-network/HttpResponse.hpp>
#include <kiwano-network/HttpClient.h>

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,283 +23,280 @@
namespace kiwano
{
namespace physics
{
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
{
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

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,366 +19,471 @@
// THE SOFTWARE.
#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/Fixture.h>
#include <kiwano-physics/Shape.h>
#include <kiwano-physics/helper.h>
namespace kiwano
{
namespace physics
{
class World;
KGE_DECLARE_SMART_PTR(Body);
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物体
class KGE_API Body
: public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 物体类型
enum class Type
{
Static = 0, ///< 静态物体
Kinematic, ///< 动力学物体
Dynamic, ///< 动态物体
};
Body();
virtual ~Body();
/// \~chinese
/// @brief 初始化
/// @param[in] world 物理世界
/// @param[in] actor 绑定的角色
bool InitBody(World* world, ActorPtr actor);
/// \~chinese
/// @brief 初始化
/// @param[in] world 物理世界
/// @param[in] actor 绑定的角色
bool InitBody(World* world, Actor* actor);
/// \~chinese
/// @brief 添加夹具
/// @param shape 物体形状
/// @param density 物体密度
Fixture AddFixture(Shape* shape, const Fixture::Param& param);
/// \~chinese
/// @brief 添加圆形夹具
/// @param radius 圆形半径
/// @param density 物体密度
Fixture AddCircleShape(float radius, float density = 0.f);
/// \~chinese
/// @brief 添加盒形夹具
/// @param size 盒大小
/// @param density 物体密度
Fixture AddBoxShape(Vec2 const& size, float density = 0.f);
/// \~chinese
/// @brief 添加多边形夹具
/// @param vertexs 多边形端点
/// @param density 物体密度
Fixture AddPolygonShape(Vector<Point> const& vertexs, float density = 0.f);
/// \~chinese
/// @brief 添加线段形夹具
/// @param p1 线段起点
/// @param p2 线段终点
/// @param density 物体密度
Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f);
/// \~chinese
/// @brief 添加链条形夹具
/// @param vertexs 链条端点
/// @param loop 是否闭合
/// @param density 物体密度
Fixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
/// \~chinese
/// @brief 获取夹具列表
FixtureList GetFixtureList() const;
/// \~chinese
/// @brief 移除夹具
void RemoveFixture(Fixture const& fixture);
/// \~chinese
/// @brief 获取接触边列表
ContactEdgeList GetContactList() const;
/// \~chinese
/// @brief 获取类别码
uint16_t GetCategoryBits() const;
/// \~chinese
/// @brief 设置类别码
void SetCategoryBits(uint16_t category_bits);
/// \~chinese
/// @brief 获取碰撞掩码
uint16_t GetMaskBits() const;
/// \~chinese
/// @brief 设置碰撞掩码
void SetMaskBits(uint16_t mask_bits);
/// \~chinese
/// @brief 获取组索引
int16_t GetGroupIndex() const;
/// \~chinese
/// @brief 设置组索引
void SetGroupIndex(int16_t index);
/// \~chinese
/// @brief 获取旋转角度
float GetBodyRotation() const;
/// \~chinese
/// @brief 设置旋转角度
void SetBodyRotation(float angle);
/// \~chinese
/// @brief 获取物体位置
Point GetBodyPosition() const;
/// \~chinese
/// @brief 设置物体位置
void SetBodyPosition(Point const& pos);
/// \~chinese
/// @brief 位置和旋转变换
void SetBodyTransform(Point const& pos, float angle);
/// \~chinese
/// @brief 获取质量 [kg]
float GetMass() const;
/// \~chinese
/// @brief 获取惯性
float GetInertia() const;
/// \~chinese
/// @brief 获取质量数据
/// @param[out] mass 物体质量 [kg]
/// @param[out] center 质心位置
/// @param[out] inertia 惯性
void GetMassData(float* mass, Point* center, float* inertia) const;
/// \~chinese
/// @brief 设置质量数据
/// @param mass 物体质量 [kg]
/// @param center 质心位置
/// @param inertia 惯性
void SetMassData(float mass, Point const& center, float inertia);
/// \~chinese
/// @brief 重置质量数据
void ResetMassData();
/// \~chinese
/// @brief 获取世界坐标系上的点在物体上的位置
Point GetLocalPoint(Point const& world) const;
/// \~chinese
/// @brief 获取物体上的点在世界坐标系的位置
Point GetWorldPoint(Point const& local) const;
/// \~chinese
/// @brief 获取物体质心相对于物体的位置
Point GetLocalCenter() const;
/// \~chinese
/// @brief 获取物体质心位置
Point GetWorldCenter() const;
/// \~chinese
/// @brief 获取物体类型
Type GetType() const;
/// \~chinese
/// @brief 设置物体类型
void SetType(Type type);
/// \~chinese
/// @brief 获取物体受重力的比例
float GetGravityScale() const;
/// \~chinese
/// @brief 设置物体受重力的比例
void SetGravityScale(float scale);
/// \~chinese
/// @brief 施力
/// @param force 力的大小和方向
/// @param point 施力点
/// @param wake 是否唤醒物体
void ApplyForce(Vec2 const& force, Point const& point, bool wake = true);
/// \~chinese
/// @brief 给物体中心施力
/// @param force 力的大小和方向
/// @param wake 是否唤醒物体
void ApplyForceToCenter(Vec2 const& force, bool wake = true);
/// \~chinese
/// @brief 施加扭矩
/// @param torque 扭矩
/// @param wake 是否唤醒物体
void ApplyTorque(float torque, bool wake = false);
/// \~chinese
/// @brief 旋转角度是否固定
bool IsIgnoreRotation() const;
/// \~chinese
/// @brief 设置是否固定旋转角度
void SetIgnoreRotation(bool flag);
/// \~chinese
/// @brief 是否是子弹物体
bool IsBullet() const;
/// \~chinese
/// @brief 设置物体是否是子弹物体
void SetBullet(bool flag);
/// \~chinese
/// @brief 是否处于唤醒状态
bool IsAwake() const;
/// \~chinese
/// @brief 设置唤醒状态
void SetAwake(bool flag);
/// \~chinese
/// @brief 是否启用休眠
bool IsSleepingAllowed() const;
/// \~chinese
/// @brief 设置是否允许休眠
void SetSleepingAllowed(bool flag);
/// \~chinese
/// @brief 是否启用
bool IsActive() const;
/// \~chinese
/// @brief 设置启用状态
void SetActive(bool flag);
/// \~chinese
/// @brief 获取物体所在物理世界
World* GetWorld() const;
/// \~chinese
/// @brief 获取物体绑定的角色
Actor* GetActor() const;
/// \~chinese
/// @brief 设置物体绑定的角色
void SetActor(Actor* actor);
/// \~chinese
/// @brief 将物体信息更新到角色
void UpdateActor();
/// \~chinese
/// @brief 将角色信息更新到物体
void UpdateFromActor();
b2Body* GetB2Body() const;
void SetB2Body(b2Body* body);
private:
/// \~chinese
/// @brief 销毁物体
void UpdateFixtureFilter(b2Fixture* fixture);
/// \~chinese
/// @brief 销毁物体
void Destroy();
private:
Actor* actor_;
World* world_;
b2Body* body_;
uint16_t category_bits_;
uint16_t mask_bits_;
int16_t group_index_;
};
/** @} */
inline bool Body::InitBody(World* world, ActorPtr actor) { return InitBody(world, actor.get()); }
inline FixtureList Body::GetFixtureList() const { KGE_ASSERT(body_); return FixtureList(Fixture(body_->GetFixtureList())); }
inline ContactEdgeList Body::GetContactList() const { KGE_ASSERT(body_); return ContactEdgeList(ContactEdge(body_->GetContactList())); }
inline uint16_t Body::GetCategoryBits() const { return category_bits_; }
inline uint16_t Body::GetMaskBits() const { return mask_bits_; }
inline int16_t Body::GetGroupIndex() const { return group_index_; }
inline float Body::GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); }
inline void Body::SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); }
inline void Body::SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); }
inline float Body::GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); }
inline float Body::GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); }
inline Body::Type Body::GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); }
inline void Body::SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast<b2BodyType>(type)); }
inline float Body::GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); }
inline void Body::SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); }
inline bool Body::IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); }
inline void Body::SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); }
inline bool Body::IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); }
inline void Body::SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); }
inline bool Body::IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); }
inline void Body::SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); }
inline bool Body::IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); }
inline void Body::SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); }
inline bool Body::IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); }
inline void Body::SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); }
inline Actor* Body::GetActor() const { return actor_; }
inline void Body::SetActor(Actor* actor) { actor_ = actor; }
inline b2Body* Body::GetB2Body() const { return body_; }
inline World* Body::GetWorld() const { return world_; }
}
namespace physics
{
class World;
KGE_DECLARE_SMART_PTR(Body);
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物体
class KGE_API Body : public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 物体类型
enum class Type
{
Static = 0, ///< 静态物体
Kinematic, ///< 动力学物体
Dynamic, ///< 动态物体
};
Body();
virtual ~Body();
/// \~chinese
/// @brief 初始化
/// @param[in] world 物理世界
/// @param[in] actor 绑定的角色
bool InitBody(World* world, ActorPtr actor);
/// \~chinese
/// @brief 初始化
/// @param[in] world 物理世界
/// @param[in] actor 绑定的角色
bool InitBody(World* world, Actor* actor);
/// \~chinese
/// @brief 添加夹具
/// @param shape 物体形状
/// @param density 物体密度
Fixture AddFixture(Shape* shape, const Fixture::Param& param);
/// \~chinese
/// @brief 添加圆形夹具
/// @param radius 圆形半径
/// @param density 物体密度
Fixture AddCircleShape(float radius, float density = 0.f);
/// \~chinese
/// @brief 添加盒形夹具
/// @param size 盒大小
/// @param density 物体密度
Fixture AddBoxShape(Vec2 const& size, float density = 0.f);
/// \~chinese
/// @brief 添加多边形夹具
/// @param vertexs 多边形端点
/// @param density 物体密度
Fixture AddPolygonShape(Vector<Point> const& vertexs, float density = 0.f);
/// \~chinese
/// @brief 添加线段形夹具
/// @param p1 线段起点
/// @param p2 线段终点
/// @param density 物体密度
Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f);
/// \~chinese
/// @brief 添加链条形夹具
/// @param vertexs 链条端点
/// @param loop 是否闭合
/// @param density 物体密度
Fixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
/// \~chinese
/// @brief 获取夹具列表
FixtureList GetFixtureList() const;
/// \~chinese
/// @brief 移除夹具
void RemoveFixture(Fixture const& fixture);
/// \~chinese
/// @brief 获取接触边列表
ContactEdgeList GetContactList() const;
/// \~chinese
/// @brief 获取类别码
uint16_t GetCategoryBits() const;
/// \~chinese
/// @brief 设置类别码
void SetCategoryBits(uint16_t category_bits);
/// \~chinese
/// @brief 获取碰撞掩码
uint16_t GetMaskBits() const;
/// \~chinese
/// @brief 设置碰撞掩码
void SetMaskBits(uint16_t mask_bits);
/// \~chinese
/// @brief 获取组索引
int16_t GetGroupIndex() const;
/// \~chinese
/// @brief 设置组索引
void SetGroupIndex(int16_t index);
/// \~chinese
/// @brief 获取旋转角度
float GetBodyRotation() const;
/// \~chinese
/// @brief 设置旋转角度
void SetBodyRotation(float angle);
/// \~chinese
/// @brief 获取物体位置
Point GetBodyPosition() const;
/// \~chinese
/// @brief 设置物体位置
void SetBodyPosition(Point const& pos);
/// \~chinese
/// @brief 位置和旋转变换
void SetBodyTransform(Point const& pos, float angle);
/// \~chinese
/// @brief 获取质量 [kg]
float GetMass() const;
/// \~chinese
/// @brief 获取惯性
float GetInertia() const;
/// \~chinese
/// @brief 获取质量数据
/// @param[out] mass 物体质量 [kg]
/// @param[out] center 质心位置
/// @param[out] inertia 惯性
void GetMassData(float* mass, Point* center, float* inertia) const;
/// \~chinese
/// @brief 设置质量数据
/// @param mass 物体质量 [kg]
/// @param center 质心位置
/// @param inertia 惯性
void SetMassData(float mass, Point const& center, float inertia);
/// \~chinese
/// @brief 重置质量数据
void ResetMassData();
/// \~chinese
/// @brief 获取世界坐标系上的点在物体上的位置
Point GetLocalPoint(Point const& world) const;
/// \~chinese
/// @brief 获取物体上的点在世界坐标系的位置
Point GetWorldPoint(Point const& local) const;
/// \~chinese
/// @brief 获取物体质心相对于物体的位置
Point GetLocalCenter() const;
/// \~chinese
/// @brief 获取物体质心位置
Point GetWorldCenter() const;
/// \~chinese
/// @brief 获取物体类型
Type GetType() const;
/// \~chinese
/// @brief 设置物体类型
void SetType(Type type);
/// \~chinese
/// @brief 获取物体受重力的比例
float GetGravityScale() const;
/// \~chinese
/// @brief 设置物体受重力的比例
void SetGravityScale(float scale);
/// \~chinese
/// @brief 施力
/// @param force 力的大小和方向
/// @param point 施力点
/// @param wake 是否唤醒物体
void ApplyForce(Vec2 const& force, Point const& point, bool wake = true);
/// \~chinese
/// @brief 给物体中心施力
/// @param force 力的大小和方向
/// @param wake 是否唤醒物体
void ApplyForceToCenter(Vec2 const& force, bool wake = true);
/// \~chinese
/// @brief 施加扭矩
/// @param torque 扭矩
/// @param wake 是否唤醒物体
void ApplyTorque(float torque, bool wake = false);
/// \~chinese
/// @brief 旋转角度是否固定
bool IsIgnoreRotation() const;
/// \~chinese
/// @brief 设置是否固定旋转角度
void SetIgnoreRotation(bool flag);
/// \~chinese
/// @brief 是否是子弹物体
bool IsBullet() const;
/// \~chinese
/// @brief 设置物体是否是子弹物体
void SetBullet(bool flag);
/// \~chinese
/// @brief 是否处于唤醒状态
bool IsAwake() const;
/// \~chinese
/// @brief 设置唤醒状态
void SetAwake(bool flag);
/// \~chinese
/// @brief 是否启用休眠
bool IsSleepingAllowed() const;
/// \~chinese
/// @brief 设置是否允许休眠
void SetSleepingAllowed(bool flag);
/// \~chinese
/// @brief 是否启用
bool IsActive() const;
/// \~chinese
/// @brief 设置启用状态
void SetActive(bool flag);
/// \~chinese
/// @brief 获取物体所在物理世界
World* GetWorld() const;
/// \~chinese
/// @brief 获取物体绑定的角色
Actor* GetActor() const;
/// \~chinese
/// @brief 设置物体绑定的角色
void SetActor(Actor* actor);
/// \~chinese
/// @brief 将物体信息更新到角色
void UpdateActor();
/// \~chinese
/// @brief 将角色信息更新到物体
void UpdateFromActor();
b2Body* GetB2Body() const;
void SetB2Body(b2Body* body);
private:
/// \~chinese
/// @brief 销毁物体
void UpdateFixtureFilter(b2Fixture* fixture);
/// \~chinese
/// @brief 销毁物体
void Destroy();
private:
Actor* actor_;
World* world_;
b2Body* body_;
uint16_t category_bits_;
uint16_t mask_bits_;
int16_t group_index_;
};
/** @} */
inline bool Body::InitBody(World* world, ActorPtr actor)
{
return InitBody(world, actor.get());
}
inline FixtureList Body::GetFixtureList() const
{
KGE_ASSERT(body_);
return FixtureList(Fixture(body_->GetFixtureList()));
}
inline ContactEdgeList Body::GetContactList() const
{
KGE_ASSERT(body_);
return ContactEdgeList(ContactEdge(body_->GetContactList()));
}
inline uint16_t Body::GetCategoryBits() const
{
return category_bits_;
}
inline uint16_t Body::GetMaskBits() const
{
return mask_bits_;
}
inline int16_t Body::GetGroupIndex() const
{
return group_index_;
}
inline float Body::GetBodyRotation() const
{
KGE_ASSERT(body_);
return math::Radian2Degree(body_->GetAngle());
}
inline void Body::SetBodyRotation(float angle)
{
SetBodyTransform(GetBodyPosition(), angle);
}
inline void Body::SetBodyPosition(Point const& pos)
{
SetBodyTransform(pos, GetBodyRotation());
}
inline float Body::GetMass() const
{
KGE_ASSERT(body_);
return body_->GetMass();
}
inline float Body::GetInertia() const
{
KGE_ASSERT(body_);
return body_->GetInertia();
}
inline Body::Type Body::GetType() const
{
KGE_ASSERT(body_);
return Type(body_->GetType());
}
inline void Body::SetType(Type type)
{
KGE_ASSERT(body_);
body_->SetType(static_cast<b2BodyType>(type));
}
inline float Body::GetGravityScale() const
{
KGE_ASSERT(body_);
return body_->GetGravityScale();
}
inline void Body::SetGravityScale(float scale)
{
KGE_ASSERT(body_);
body_->SetGravityScale(scale);
}
inline bool Body::IsIgnoreRotation() const
{
KGE_ASSERT(body_);
return body_->IsFixedRotation();
}
inline void Body::SetIgnoreRotation(bool flag)
{
KGE_ASSERT(body_);
body_->SetFixedRotation(flag);
}
inline bool Body::IsBullet() const
{
KGE_ASSERT(body_);
return body_->IsBullet();
}
inline void Body::SetBullet(bool flag)
{
KGE_ASSERT(body_);
body_->SetBullet(flag);
}
inline bool Body::IsAwake() const
{
KGE_ASSERT(body_);
return body_->IsAwake();
}
inline void Body::SetAwake(bool flag)
{
KGE_ASSERT(body_);
body_->SetAwake(flag);
}
inline bool Body::IsSleepingAllowed() const
{
KGE_ASSERT(body_);
return body_->IsSleepingAllowed();
}
inline void Body::SetSleepingAllowed(bool flag)
{
KGE_ASSERT(body_);
body_->SetSleepingAllowed(flag);
}
inline bool Body::IsActive() const
{
KGE_ASSERT(body_);
return body_->IsActive();
}
inline void Body::SetActive(bool flag)
{
KGE_ASSERT(body_);
body_->SetActive(flag);
}
inline Actor* Body::GetActor() const
{
return actor_;
}
inline void Body::SetActor(Actor* actor)
{
actor_ = actor;
}
inline b2Body* Body::GetB2Body() const
{
return body_;
}
inline World* Body::GetWorld() const
{
return world_;
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -18,73 +18,73 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/World.h>
namespace kiwano
{
namespace physics
{
namespace physics
{
Contact::Contact()
: 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()
: 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());
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,232 +19,277 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/helper.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/helper.h>
namespace kiwano
{
namespace physics
{
class Body;
namespace physics
{
class Body;
/**
* \addtogroup Physics
* @{
*/
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物理接触
class KGE_API Contact
{
public:
Contact();
Contact(b2Contact* contact);
/// \~chinese
/// @brief 物理接触
class KGE_API Contact
{
public:
Contact();
Contact(b2Contact* contact);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 是否是接触
bool IsTouching() const;
/// \~chinese
/// @brief 是否是接触
bool IsTouching() const;
/// \~chinese
/// @brief 启用或禁用 (仅作用于一个时间步)
void SetEnabled(bool flag);
/// \~chinese
/// @brief 启用或禁用 (仅作用于一个时间步)
void SetEnabled(bool flag);
/// \~chinese
/// @brief 是否启用
bool IsEnabled() const;
/// \~chinese
/// @brief 是否启用
bool IsEnabled() const;
/// \~chinese
/// @brief 获取物体A的夹具
Fixture GetFixtureA() const;
/// \~chinese
/// @brief 获取物体A的夹具
Fixture GetFixtureA() const;
/// \~chinese
/// @brief 获取物体B的夹具
Fixture GetFixtureB() const;
/// \~chinese
/// @brief 获取物体B的夹具
Fixture GetFixtureB() const;
/// \~chinese
/// @brief 获取物体A
Body* GetBodyA() const;
/// \~chinese
/// @brief 获取物体A
Body* GetBodyA() const;
/// \~chinese
/// @brief 获取物体B
Body* GetBodyB() const;
/// \~chinese
/// @brief 获取物体B
Body* GetBodyB() const;
/// \~chinese
/// @brief 设置摩擦力
void SetFriction(float friction);
/// \~chinese
/// @brief 设置摩擦力
void SetFriction(float friction);
/// \~chinese
/// @brief 获取摩擦力
float GetFriction() const;
/// \~chinese
/// @brief 获取摩擦力
float GetFriction() const;
/// \~chinese
/// @brief 重置摩擦力
void ResetFriction();
/// \~chinese
/// @brief 重置摩擦力
void ResetFriction();
/// \~chinese
/// @brief 设置弹性恢复
void SetRestitution(float restitution);
/// \~chinese
/// @brief 设置弹性恢复
void SetRestitution(float restitution);
/// \~chinese
/// @brief 获取弹性恢复
float GetRestitution() const;
/// \~chinese
/// @brief 获取弹性恢复
float GetRestitution() const;
/// \~chinese
/// @brief 重置弹性恢复
void ResetRestitution();
/// \~chinese
/// @brief 重置弹性恢复
void ResetRestitution();
/// \~chinese
/// @brief 设置切线速度
void SetTangentSpeed(float speed);
/// \~chinese
/// @brief 设置切线速度
void SetTangentSpeed(float speed);
/// \~chinese
/// @brief 获取切线速度
float GetTangentSpeed() const;
/// \~chinese
/// @brief 获取切线速度
float GetTangentSpeed() const;
b2Contact* GetB2Contact() const;
void SetB2Contact(b2Contact* contact);
b2Contact* GetB2Contact() const;
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:
b2Contact* contact_;
};
private:
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
/// @brief 物理接触列表
class ContactList
: public List<Contact>
{
template <typename _Ty>
class IteratorImpl
: public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
public:
IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
public:
IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
}
inline IteratorImpl& operator++()
{
elem_ = elem_.GetB2Contact()->GetNext();
return *this;
}
inline IteratorImpl& operator++()
{
elem_ = elem_.GetB2Contact()->GetNext();
return *this;
}
inline IteratorImpl operator++(int)
{
IteratorImpl old = *this;
operator++();
return old;
}
inline IteratorImpl operator++(int)
{
IteratorImpl old = *this;
operator++();
return old;
}
inline bool operator==(const IteratorImpl& rhs) const
{
return elem_ == rhs.elem_;
}
inline bool operator== (const IteratorImpl& rhs) const
{
return elem_ == rhs.elem_;
}
inline bool operator!=(const IteratorImpl& rhs) const
{
return !operator==(rhs);
}
inline bool operator!= (const IteratorImpl& rhs) const
{
return !operator==(rhs);
}
private:
_Ty elem_;
};
private:
_Ty elem_;
};
public:
using value_type = Contact;
using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
public:
using value_type = Contact;
using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
inline ContactList() {}
inline ContactList()
{
}
inline ContactList(const value_type& first)
: first_(first)
{
}
inline ContactList(const value_type& first)
: first_(first)
{
}
inline const value_type& front() const
{
return first_;
}
inline const value_type& front() const
{
return first_;
}
inline value_type& front()
{
return first_;
}
inline value_type& front()
{
return first_;
}
inline iterator begin()
{
return iterator(first_);
}
inline iterator begin()
{
return iterator(first_);
}
inline const_iterator begin() const
{
return cbegin();
}
inline const_iterator begin() const
{
return cbegin();
}
inline const_iterator cbegin() const
{
return const_iterator(first_);
}
inline const_iterator cbegin() const
{
return const_iterator(first_);
}
inline iterator end()
{
return iterator(nullptr);
}
inline iterator end()
{
return iterator(nullptr);
}
inline const_iterator end() const
{
return cend();
}
inline const_iterator end() const
{
return cend();
}
inline const_iterator cend() const
{
return const_iterator(nullptr);
}
inline const_iterator cend() const
{
return const_iterator(nullptr);
}
private:
value_type first_;
};
private:
value_type first_;
};
/** @} */
/** @} */
inline bool Contact::IsValid() const { return contact_ != nullptr;}
inline bool Contact::IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); }
inline void Contact::SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); }
inline bool Contact::IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); }
inline void Contact::SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); }
inline float Contact::GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); }
inline void Contact::ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); }
inline void Contact::SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); }
inline float Contact::GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); }
inline void Contact::ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); }
inline b2Contact* Contact::GetB2Contact() const { return contact_; }
inline void Contact::SetB2Contact(b2Contact* contact) { contact_ = contact; }
inline bool Contact::operator==(const Contact& rhs) const { return contact_ == rhs.contact_; }
inline bool Contact::operator!=(const Contact& rhs) const { return contact_ != rhs.contact_; }
}
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_;
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -22,19 +22,19 @@
namespace kiwano
{
namespace physics
{
namespace physics
{
ContactEdge::ContactEdge()
: edge_(nullptr)
{
}
ContactEdge::ContactEdge(b2ContactEdge* edge)
: ContactEdge()
{
SetB2ContactEdge(edge);
}
}
ContactEdge::ContactEdge()
: edge_(nullptr)
{
}
ContactEdge::ContactEdge(b2ContactEdge* edge)
: ContactEdge()
{
SetB2ContactEdge(edge);
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,164 +23,183 @@
namespace kiwano
{
namespace physics
{
/**
* \addtogroup Physics
* @{
*/
namespace physics
{
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 接触边
class KGE_API ContactEdge
{
public:
ContactEdge();
ContactEdge(b2ContactEdge* edge);
/// \~chinese
/// @brief 接触边
class KGE_API ContactEdge
{
public:
ContactEdge();
ContactEdge(b2ContactEdge* edge);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 获取接触物体
Body* GetOtherBody() const;
/// \~chinese
/// @brief 获取接触物体
Body* GetOtherBody() const;
/// \~chinese
/// @brief 获取接触
Contact GetContact() const;
/// \~chinese
/// @brief 获取接触
Contact GetContact() const;
b2ContactEdge* GetB2ContactEdge() const;
void SetB2ContactEdge(b2ContactEdge* edge);
b2ContactEdge* GetB2ContactEdge() const;
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:
b2ContactEdge* edge_;
};
private:
b2ContactEdge* edge_;
};
/// \~chinese
/// @brief 物理接触边列表
class ContactEdgeList
{
template <typename _Ty>
class IteratorImpl : public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
/// \~chinese
/// @brief 物理接触边列表
class ContactEdgeList
{
template <typename _Ty>
class IteratorImpl
: public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
public:
inline IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
public:
inline IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
}
inline IteratorImpl& operator++()
{
elem_ = elem_.GetB2ContactEdge()->next;
return *this;
}
inline IteratorImpl& operator++()
{
elem_ = elem_.GetB2ContactEdge()->next;
return *this;
}
inline IteratorImpl operator++(int)
{
IteratorImpl old = *this;
operator++();
return old;
}
inline IteratorImpl operator++(int)
{
IteratorImpl old = *this;
operator++();
return old;
}
inline bool operator==(const IteratorImpl& rhs) const
{
return elem_ == rhs.elem_;
}
inline bool operator== (const IteratorImpl& rhs) const
{
return elem_ == rhs.elem_;
}
inline bool operator!=(const IteratorImpl& rhs) const
{
return !operator==(rhs);
}
inline bool operator!= (const IteratorImpl& rhs) const
{
return !operator==(rhs);
}
private:
_Ty elem_;
};
private:
_Ty elem_;
};
public:
using value_type = ContactEdge;
using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
public:
using value_type = ContactEdge;
using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
inline ContactEdgeList() {}
inline ContactEdgeList()
{
}
inline ContactEdgeList(const value_type& first)
: first_(first)
{
}
inline ContactEdgeList(const value_type& first)
: first_(first)
{
}
inline const value_type& front() const
{
return first_;
}
inline const value_type& front() const
{
return first_;
}
inline value_type& front()
{
return first_;
}
inline value_type& front()
{
return first_;
}
inline iterator begin()
{
return iterator(first_);
}
inline iterator begin()
{
return iterator(first_);
}
inline const_iterator begin() const
{
return cbegin();
}
inline const_iterator begin() const
{
return cbegin();
}
inline const_iterator cbegin() const
{
return const_iterator(first_);
}
inline const_iterator cbegin() const
{
return const_iterator(first_);
}
inline iterator end()
{
return iterator(nullptr);
}
inline iterator end()
{
return iterator(nullptr);
}
inline const_iterator end() const
{
return cend();
}
inline const_iterator end() const
{
return cend();
}
inline const_iterator cend() const
{
return const_iterator(nullptr);
}
inline const_iterator cend() const
{
return const_iterator(nullptr);
}
private:
value_type first_;
};
private:
value_type first_;
};
/** @} */
/** @} */
inline bool ContactEdge::IsValid() const { return edge_ != nullptr; }
inline Body* ContactEdge::GetOtherBody() const { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
inline Contact ContactEdge::GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); }
inline b2ContactEdge* ContactEdge::GetB2ContactEdge() const { return edge_; }
inline void ContactEdge::SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; }
inline bool ContactEdge::operator==(const ContactEdge& rhs) const { return edge_ == rhs.edge_; }
inline bool ContactEdge::operator!=(const ContactEdge& rhs) const { return edge_ != rhs.edge_; }
}
inline bool ContactEdge::IsValid() const
{
return edge_ != nullptr;
}
inline Body* ContactEdge::GetOtherBody() const
{
KGE_ASSERT(edge_);
return static_cast<Body*>(edge_->other->GetUserData());
}
inline Contact ContactEdge::GetContact() const
{
KGE_ASSERT(edge_);
return Contact(edge_->contact);
}
inline b2ContactEdge* ContactEdge::GetB2ContactEdge() const
{
return edge_;
}
inline void ContactEdge::SetB2ContactEdge(b2ContactEdge* edge)
{
edge_ = edge;
}
inline bool ContactEdge::operator==(const ContactEdge& rhs) const
{
return edge_ == rhs.edge_;
}
inline bool ContactEdge::operator!=(const ContactEdge& rhs) const
{
return edge_ != rhs.edge_;
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -22,29 +22,29 @@
namespace kiwano
{
namespace physics
{
ContactBeginEvent::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;
}
namespace physics
{
ContactBeginEvent::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;
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,47 +19,45 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/Contact.h>
namespace kiwano
{
namespace physics
{
KGE_DECLARE_SMART_PTR(ContactBeginEvent);
KGE_DECLARE_SMART_PTR(ContactEndEvent);
namespace physics
{
KGE_DECLARE_SMART_PTR(ContactBeginEvent);
KGE_DECLARE_SMART_PTR(ContactEndEvent);
/**
* \addtogroup Events
* @{
*/
/**
* \addtogroup Events
* @{
*/
/// \~chinese
/// @brief 物理接触开始事件
class KGE_API ContactBeginEvent
: public Event
{
public:
Contact contact; ///< 产生的接触
/// \~chinese
/// @brief 物理接触开始事件
class KGE_API ContactBeginEvent : public Event
{
public:
Contact contact; ///< 产生的接触
ContactBeginEvent();
ContactBeginEvent();
ContactBeginEvent(Contact const& contact);
};
ContactBeginEvent(Contact const& contact);
};
/// \~chinese
/// @brief 物理接触结束事件
class KGE_API ContactEndEvent
: public Event
{
public:
Contact contact; ///< 产生的接触
/// \~chinese
/// @brief 物理接触结束事件
class KGE_API ContactEndEvent : public Event
{
public:
Contact contact; ///< 产生的接触
ContactEndEvent();
ContactEndEvent();
ContactEndEvent(Contact const& contact);
};
ContactEndEvent(Contact const& contact);
};
/** @} */
}
}
/** @} */
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -18,88 +18,91 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/World.h>
namespace kiwano
{
namespace physics
{
namespace physics
{
Fixture::Fixture()
: 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()
: 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));
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,237 +19,281 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/helper.h>
#include <kiwano-physics/Shape.h>
#include <kiwano-physics/helper.h>
namespace kiwano
{
namespace physics
{
class Body;
namespace physics
{
class Body;
/**
* \addtogroup Physics
* @{
*/
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物理夹具
class Fixture
{
public:
/// \~chinese
/// @brief 夹具参数
struct Param
{
float density = 0.f; ///< 密度
float friction = 0.2f; ///< 摩擦力
float restitution = 0.f; ///< 弹性恢复
bool is_sensor = false; ///< 是否是接触传感器
/// \~chinese
/// @brief 物理夹具
class Fixture
{
public:
/// \~chinese
/// @brief 夹具参数
struct Param
{
float density = 0.f; ///< 密度
float friction = 0.2f; ///< 摩擦力
float restitution = 0.f; ///< 弹性恢复
bool is_sensor = false; ///< 是否是接触传感器
Param() {}
Param() {}
Param(float density, float friction = 0.2f, float restitution = 0.f, bool is_sensor = false)
: density(density)
, friction(friction)
, restitution(restitution)
, is_sensor(is_sensor)
{}
};
Param(float density, float friction = 0.2f, float restitution = 0.f, bool is_sensor = false)
: density(density)
, friction(friction)
, restitution(restitution)
, is_sensor(is_sensor)
{
}
};
Fixture();
Fixture(b2Fixture* fixture);
Fixture(Body* body, Shape* shape, const Param& param);
Fixture();
Fixture(b2Fixture* fixture);
Fixture(Body* body, Shape* shape, const Param& param);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
/// \~chinese
/// @brief 获取夹具所在的物体
Body* GetBody() const;
/// \~chinese
/// @brief 获取夹具所在的物体
Body* GetBody() const;
/// \~chinese
/// @brief 形状
Shape GetShape() const;
/// \~chinese
/// @brief 形状
Shape GetShape() const;
/// \~chinese
/// @brief 是否是接触传感器
bool IsSensor() const;
/// \~chinese
/// @brief 是否是接触传感器
bool IsSensor() const;
/// \~chinese
/// @brief 设置夹具是否是接触传感器
/// @details 接触传感器只会产生物理接触,而不会影响物体运动
void SetSensor(bool sensor);
/// \~chinese
/// @brief 设置夹具是否是接触传感器
/// @details 接触传感器只会产生物理接触,而不会影响物体运动
void SetSensor(bool sensor);
/// \~chinese
/// @brief 获取夹具的质量数据
void GetMassData(float* mass, Point* center, float* inertia) const;
/// \~chinese
/// @brief 获取夹具的质量数据
void GetMassData(float* mass, Point* center, float* inertia) const;
/// \~chinese
/// @brief 获取密度
float GetDensity() const;
/// \~chinese
/// @brief 获取密度
float GetDensity() const;
/// \~chinese
/// @brief 设置密度
void SetDensity(float density);
/// \~chinese
/// @brief 设置密度
void SetDensity(float density);
/// \~chinese
/// @brief 获取摩擦力 [N]
float GetFriction() const;
/// \~chinese
/// @brief 获取摩擦力 [N]
float GetFriction() const;
/// \~chinese
/// @brief 设置摩擦力 [N]
void SetFriction(float friction);
/// \~chinese
/// @brief 设置摩擦力 [N]
void SetFriction(float friction);
/// \~chinese
/// @brief 获取弹性恢复
float GetRestitution() const;
/// \~chinese
/// @brief 获取弹性恢复
float GetRestitution() const;
/// \~chinese
/// @brief 设置弹性恢复
void SetRestitution(float restitution);
/// \~chinese
/// @brief 设置弹性恢复
void SetRestitution(float restitution);
/// \~chinese
/// @brief 点测试
bool TestPoint(const Point& p) const;
/// \~chinese
/// @brief 点测试
bool TestPoint(const Point& p) const;
b2Fixture* GetB2Fixture() const;
void SetB2Fixture(b2Fixture* fixture);
b2Fixture* GetB2Fixture() const;
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:
b2Fixture* fixture_;
};
private:
b2Fixture* fixture_;
};
/// \~chinese
/// @brief 物理夹具列表
class FixtureList
: public List<Fixture>
{
template <typename _Ty>
class IteratorImpl
: public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
/// \~chinese
/// @brief 物理夹具列表
class FixtureList : public List<Fixture>
{
template <typename _Ty>
class IteratorImpl : public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
public:
IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
public:
IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
}
inline IteratorImpl& operator++()
{
elem_ = elem_.GetB2Fixture()->GetNext();
return *this;
}
inline IteratorImpl& operator++()
{
elem_ = elem_.GetB2Fixture()->GetNext();
return *this;
}
inline IteratorImpl operator++(int)
{
IteratorImpl old = *this;
operator++();
return old;
}
inline IteratorImpl operator++(int)
{
IteratorImpl old = *this;
operator++();
return old;
}
inline bool operator== (const IteratorImpl& rhs) const
{
return elem_ == rhs.elem_;
}
inline bool operator==(const IteratorImpl& rhs) const
{
return elem_ == rhs.elem_;
}
inline bool operator!= (const IteratorImpl& rhs) const
{
return !operator==(rhs);
}
inline bool operator!=(const IteratorImpl& rhs) const
{
return !operator==(rhs);
}
private:
_Ty elem_;
};
private:
_Ty elem_;
};
public:
using value_type = Fixture;
using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
public:
using value_type = Fixture;
using iterator = IteratorImpl<value_type>;
using const_iterator = IteratorImpl<const value_type>;
inline FixtureList()
{
}
inline FixtureList() {}
inline FixtureList(const value_type& first)
: first_(first)
{
}
inline FixtureList(const value_type& first)
: first_(first)
{
}
inline const value_type& front() const
{
return first_;
}
inline const value_type& front() const
{
return first_;
}
inline value_type& front()
{
return first_;
}
inline value_type& front()
{
return first_;
}
inline iterator begin()
{
return iterator(first_);
}
inline iterator begin()
{
return iterator(first_);
}
inline const_iterator begin() const
{
return cbegin();
}
inline const_iterator begin() const
{
return cbegin();
}
inline const_iterator cbegin() const
{
return const_iterator(first_);
}
inline const_iterator cbegin() const
{
return const_iterator(first_);
}
inline iterator end()
{
return iterator(nullptr);
}
inline iterator end()
{
return iterator(nullptr);
}
inline const_iterator end() const
{
return cend();
}
inline const_iterator end() const
{
return cend();
}
inline const_iterator cend() const
{
return const_iterator(nullptr);
}
inline const_iterator cend() const
{
return const_iterator(nullptr);
}
private:
value_type first_;
};
private:
value_type first_;
};
/** @} */
/** @} */
inline bool Fixture::IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); }
inline void Fixture::SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); }
inline float Fixture::GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); }
inline void Fixture::SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); }
inline float Fixture::GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); }
inline void Fixture::SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); }
inline float Fixture::GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); }
inline void Fixture::SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); }
inline bool Fixture::IsValid() const { return fixture_ != nullptr; }
inline b2Fixture* Fixture::GetB2Fixture() const { return fixture_; }
inline void Fixture::SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; }
inline bool Fixture::operator==(const Fixture& rhs) const { return fixture_ == rhs.fixture_; }
inline bool Fixture::operator!=(const Fixture& rhs) const { return fixture_ != rhs.fixture_; }
}
inline bool Fixture::IsSensor() const
{
KGE_ASSERT(fixture_);
return fixture_->IsSensor();
}
inline void Fixture::SetSensor(bool sensor)
{
KGE_ASSERT(fixture_);
fixture_->SetSensor(sensor);
}
inline float Fixture::GetDensity() const
{
KGE_ASSERT(fixture_);
return fixture_->GetDensity();
}
inline void Fixture::SetDensity(float density)
{
KGE_ASSERT(fixture_);
fixture_->SetDensity(density);
}
inline float Fixture::GetFriction() const
{
KGE_ASSERT(fixture_);
return fixture_->GetFriction();
}
inline void Fixture::SetFriction(float friction)
{
KGE_ASSERT(fixture_);
fixture_->SetFriction(friction);
}
inline float Fixture::GetRestitution() const
{
KGE_ASSERT(fixture_);
return fixture_->GetRestitution();
}
inline void Fixture::SetRestitution(float restitution)
{
KGE_ASSERT(fixture_);
fixture_->SetRestitution(restitution);
}
inline bool Fixture::IsValid() const
{
return fixture_ != nullptr;
}
inline b2Fixture* Fixture::GetB2Fixture() const
{
return fixture_;
}
inline void Fixture::SetB2Fixture(b2Fixture* fixture)
{
fixture_ = fixture;
}
inline bool Fixture::operator==(const Fixture& rhs) const
{
return fixture_ == rhs.fixture_;
}
inline bool Fixture::operator!=(const Fixture& rhs) const
{
return fixture_ != rhs.fixture_;
}
} // namespace physics
} // namespace kiwano

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,200 +23,200 @@
namespace kiwano
{
namespace physics
{
Shape::Shape()
: 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()));
}
}
namespace physics
{
Shape::Shape()
: 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()));
}
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -23,140 +23,135 @@
namespace kiwano
{
namespace physics
{
class World;
class Fixture;
namespace physics
{
class World;
class Fixture;
/**
* \addtogroup Physics
* @{
*/
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 形状基类
class KGE_API Shape
{
friend class Fixture;
/// \~chinese
/// @brief 形状基类
class KGE_API Shape
{
friend class Fixture;
public:
Shape();
Shape(b2Shape* shape);
public:
Shape();
Shape(b2Shape* shape);
b2Shape* GetB2Shape() const;
void SetB2Shape(b2Shape* shape);
b2Shape* GetB2Shape() const;
void SetB2Shape(b2Shape* shape);
private:
virtual void FitWorld(World* world) {}
private:
virtual void FitWorld(World* world) {}
private:
b2Shape* shape_;
};
private:
b2Shape* shape_;
};
/// \~chinese
/// @brief 圆形形状
class KGE_API CircleShape
: public Shape
{
public:
CircleShape();
/// \~chinese
/// @brief 圆形形状
class KGE_API CircleShape : public Shape
{
public:
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:
void FitWorld(World* world) override;
private:
void FitWorld(World* world) override;
private:
float radius_;
Point offset_;
b2CircleShape circle_;
};
private:
float radius_;
Point offset_;
b2CircleShape circle_;
};
/// \~chinese
/// @brief 盒子形状
class KGE_API BoxShape
: public Shape
{
public:
BoxShape();
/// \~chinese
/// @brief 盒子形状
class KGE_API BoxShape : public Shape
{
public:
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:
void FitWorld(World* world) override;
private:
void FitWorld(World* world) override;
private:
float rotation_;
Vec2 box_size_;
Point offset_;
b2PolygonShape polygon_;
};
private:
float rotation_;
Vec2 box_size_;
Point offset_;
b2PolygonShape polygon_;
};
/// \~chinese
/// @brief 多边形形状
class KGE_API PolygonShape
: public Shape
{
public:
PolygonShape();
/// \~chinese
/// @brief 多边形形状
class KGE_API PolygonShape : public Shape
{
public:
PolygonShape();
PolygonShape(Vector<Point> const& vertexs);
PolygonShape(Vector<Point> const& vertexs);
void Set(Vector<Point> const& vertexs);
void Set(Vector<Point> const& vertexs);
private:
void FitWorld(World* world) override;
private:
void FitWorld(World* world) override;
private:
Vector<Point> vertexs_;
b2PolygonShape polygon_;
};
private:
Vector<Point> vertexs_;
b2PolygonShape polygon_;
};
/// \~chinese
/// @brief 线段形状, 用于表示一条边
class KGE_API EdgeShape
: public Shape
{
public:
EdgeShape();
/// \~chinese
/// @brief 线段形状, 用于表示一条边
class KGE_API EdgeShape : public Shape
{
public:
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:
void FitWorld(World* world) override;
private:
void FitWorld(World* world) override;
private:
Point p_[2];
b2EdgeShape edge_;
};
private:
Point p_[2];
b2EdgeShape edge_;
};
/// \~chinese
/// @brief 链式形状
class KGE_API ChainShape
: public Shape
{
public:
ChainShape();
/// \~chinese
/// @brief 链式形状
class KGE_API ChainShape : public Shape
{
public:
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:
void FitWorld(World* world) override;
private:
void FitWorld(World* world) override;
private:
bool loop_;
Vector<Point> vertexs_;
b2ChainShape chain_;
};
private:
bool loop_;
Vector<Point> vertexs_;
b2ChainShape chain_;
};
/** @} */
}
}
/** @} */
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,235 +19,237 @@
// THE SOFTWARE.
#include "World.h"
#include <kiwano-physics/ContactEvent.h>
namespace kiwano
{
namespace physics
{
namespace
{
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
{
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
{
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
{
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

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -24,176 +24,174 @@
namespace kiwano
{
namespace physics
{
KGE_DECLARE_SMART_PTR(World);
namespace physics
{
KGE_DECLARE_SMART_PTR(World);
/**
* \~chinese
* \defgroup Physics
*/
/**
* \~chinese
* \defgroup Physics
*/
/**
* \addtogroup Physics
* @{
*/
/**
* \addtogroup Physics
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API World
: public Stage
{
friend class Body;
friend class Joint;
/**
* \~chinese
* @brief
*/
class KGE_API World : public Stage
{
friend class Body;
friend class Joint;
public:
World();
public:
World();
virtual ~World();
virtual ~World();
/// \~chinese
/// @brief 获取重力 [N]
Vec2 GetGravity() const;
/// \~chinese
/// @brief 获取重力 [N]
Vec2 GetGravity() const;
/// \~chinese
/// @brief 设置重力 [N]
void SetGravity(Vec2 gravity);
/// \~chinese
/// @brief 设置重力 [N]
void SetGravity(Vec2 gravity);
/// \~chinese
/// @brief 获取物理接触列表
ContactList GetContactList();
/// \~chinese
/// @brief 获取物理接触列表
ContactList GetContactList();
/// \~chinese
/// @brief 获取全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
float GetGlobalScale() const;
/// \~chinese
/// @brief 获取全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
float GetGlobalScale() const;
/// \~chinese
/// @brief 设置全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
void SetGlobalScale(float scale);
/// \~chinese
/// @brief 设置全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
void SetGlobalScale(float scale);
/// \~chinese
/// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
float World2Stage(float value) const;
/// \~chinese
/// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
float World2Stage(float value) const;
/// \~chinese
/// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
Vec2 World2Stage(const b2Vec2& pos) const;
/// \~chinese
/// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
Vec2 World2Stage(const b2Vec2& pos) const;
/// \~chinese
/// @brief 物理世界单位转换为游戏世界单位
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
float Stage2World(float value) const;
/// \~chinese
/// @brief 物理世界单位转换为游戏世界单位
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
float Stage2World(float value) const;
/// \~chinese
/// @brief 物理世界单位转换为游戏世界单位
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
b2Vec2 Stage2World(const Vec2& pos) const;
/// \~chinese
/// @brief 物理世界单位转换为游戏世界单位
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
b2Vec2 Stage2World(const Vec2& pos) const;
/// \~chinese
/// @brief 设置速度迭代次数, 默认为 6
void SetVelocityIterations(int vel_iter);
/// \~chinese
/// @brief 设置速度迭代次数, 默认为 6
void SetVelocityIterations(int vel_iter);
/// \~chinese
/// @brief 设置位置迭代次数, 默认为 2
void SetPositionIterations(int pos_iter);
/// \~chinese
/// @brief 设置位置迭代次数, 默认为 2
void SetPositionIterations(int pos_iter);
b2World* GetB2World();
b2World* GetB2World();
const b2World* GetB2World() const;
const b2World* GetB2World() const;
private:
/// \~chinese
/// @brief 移除物体
void RemoveBody(Body* body);
private:
/// \~chinese
/// @brief 移除物体
void RemoveBody(Body* body);
/// \~chinese
/// @brief 移除所有物体
void RemoveAllBodies();
/// \~chinese
/// @brief 移除所有物体
void RemoveAllBodies();
/// \~chinese
/// @brief 添加关节
void AddJoint(Joint* joint);
/// \~chinese
/// @brief 添加关节
void AddJoint(Joint* joint);
/// \~chinese
/// @brief 移除关节
void RemoveJoint(Joint* joint);
/// \~chinese
/// @brief 移除关节
void RemoveJoint(Joint* joint);
/// \~chinese
/// @brief 移除所有关节
void RemoveAllJoints();
/// \~chinese
/// @brief 移除所有关节
void RemoveAllJoints();
/// \~chinese
/// @brief 关节被移除
void JointRemoved(b2Joint* joint);
/// \~chinese
/// @brief 关节被移除
void JointRemoved(b2Joint* joint);
protected:
void Update(Duration dt) override;
protected:
void Update(Duration dt) override;
private:
b2World world_;
int vel_iter_;
int pos_iter_;
float global_scale_;
private:
b2World world_;
int vel_iter_;
int pos_iter_;
float global_scale_;
class DestructionListener;
friend DestructionListener;
DestructionListener* destruction_listener_;
class DestructionListener;
friend DestructionListener;
DestructionListener* destruction_listener_;
class ContactListener;
friend ContactListener;
ContactListener* contact_listener_;
class ContactListener;
friend ContactListener;
ContactListener* contact_listener_;
bool removing_joint_;
Vector<Joint*> joints_;
};
bool removing_joint_;
Vector<Joint*> joints_;
};
/** @} */
/** @} */
inline float World::GetGlobalScale() const
{
return global_scale_;
}
inline void World::SetGlobalScale(float scale)
{
global_scale_ = scale;
}
inline float World::World2Stage(float value) const
{
return value * GetGlobalScale();
}
inline Vec2 World::World2Stage(const b2Vec2& pos) const
{
return Point(World2Stage(pos.x), World2Stage(pos.y));
}
inline float World::Stage2World(float value) const
{
return value / GetGlobalScale();
}
inline b2Vec2 World::Stage2World(const Vec2& pos) const
{
return b2Vec2(Stage2World(pos.x), Stage2World(pos.y));
}
inline void World::SetVelocityIterations(int vel_iter)
{
vel_iter_ = vel_iter;
}
inline void World::SetPositionIterations(int pos_iter)
{
pos_iter_ = pos_iter;
}
}
inline float World::GetGlobalScale() const
{
return global_scale_;
}
inline void World::SetGlobalScale(float scale)
{
global_scale_ = scale;
}
inline float World::World2Stage(float value) const
{
return value * GetGlobalScale();
}
inline Vec2 World::World2Stage(const b2Vec2& pos) const
{
return Point(World2Stage(pos.x), World2Stage(pos.y));
}
inline float World::Stage2World(float value) const
{
return value / GetGlobalScale();
}
inline b2Vec2 World::Stage2World(const Vec2& pos) const
{
return b2Vec2(Stage2World(pos.x), Stage2World(pos.y));
}
inline void World::SetVelocityIterations(int vel_iter)
{
vel_iter_ = vel_iter;
}
inline void World::SetPositionIterations(int pos_iter)
{
pos_iter_ = pos_iter;
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -26,9 +26,15 @@
namespace kiwano
{
namespace physics
{
inline b2Vec2 Stage2World(const Vec2& pos) { return b2Vec2(pos.x, pos.y); }
inline Vec2 World2Stage(const b2Vec2& pos) { return Vec2(pos.x, pos.y); }
}
namespace physics
{
inline b2Vec2 Stage2World(const Vec2& pos)
{
return b2Vec2(pos.x, pos.y);
}
inline Vec2 World2Stage(const b2Vec2& pos)
{
return Vec2(pos.x, pos.y);
}
} // namespace physics
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -20,10 +20,10 @@
#pragma once
#include <kiwano-physics/Shape.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/ContactEvent.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Joint.h>
#include <kiwano-physics/Shape.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

View File

@ -1,15 +1,15 @@
// 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
@ -24,186 +24,184 @@
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);
}
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

View File

@ -1,15 +1,15 @@
// 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
@ -24,144 +24,141 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Button);
KGE_DECLARE_SMART_PTR(SpriteButton);
KGE_DECLARE_SMART_PTR(TextButton);
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 */)>;
/**
* \~chinese
* @brief
*/
class KGE_API Button : public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 按钮回调函数
using Callback = Function<void(Button* /* self */)>;
Button();
Button();
/// \~chinese
/// @brief 构造按钮
/// @param click 按钮点击回调函数
explicit Button(Callback const& click);
/// \~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);
/// \~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();
virtual ~Button();
/// \~chinese
/// @brief 获取按钮状态是启用还是禁用
bool IsEnable() const;
/// \~chinese
/// @brief 获取按钮状态是启用还是禁用
bool IsEnable() const;
/// \~chinese
/// @brief 设置按钮启用或禁用
void SetEnabled(bool enabled);
/// \~chinese
/// @brief 设置按钮启用或禁用
void SetEnabled(bool enabled);
/// \~chinese
/// @brief 设置按钮点击后的回调函数
void SetClickCallback(const Callback& func);
/// \~chinese
/// @brief 设置按钮点击后的回调函数
void SetClickCallback(const Callback& func);
/// \~chinese
/// @brief 设置按钮被按下时的回调函数
void SetPressedCallback(const Callback& func);
/// \~chinese
/// @brief 设置按钮被按下时的回调函数
void SetPressedCallback(const Callback& func);
/// \~chinese
/// @brief 设置按钮被抬起时的回调函数
void SetReleasedCallback(const Callback& func);
/// \~chinese
/// @brief 设置按钮被抬起时的回调函数
void SetReleasedCallback(const Callback& func);
/// \~chinese
/// @brief 设置鼠标移入按钮时的回调函数
void SetMouseOverCallback(const Callback& func);
/// \~chinese
/// @brief 设置鼠标移入按钮时的回调函数
void SetMouseOverCallback(const Callback& func);
/// \~chinese
/// @brief 设置鼠标移出按钮时的回调函数
void SetMouseOutCallback(const Callback& func);
/// \~chinese
/// @brief 设置鼠标移出按钮时的回调函数
void SetMouseOutCallback(const Callback& func);
/// \~chinese
/// @brief 按钮状态
enum class Status
{
Normal, ///< 普通
Hover, ///< 鼠标在按钮内
Pressed ///< 被按下
};
/// \~chinese
/// @brief 按钮状态
enum class Status
{
Normal, ///< 普通
Hover, ///< 鼠标在按钮内
Pressed ///< 被按下
};
/// \~chinese
/// @brief 设置按钮状态
void SetStatus(Status status);
/// \~chinese
/// @brief 设置按钮状态
void SetStatus(Status status);
/// \~chinese
/// @brief 获取按钮状态
Status GetStatus() const;
/// \~chinese
/// @brief 获取按钮状态
Status GetStatus() const;
protected:
/// \~chinese
/// @brief 更新按钮状态
void UpdateStatus(Event* evt);
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_;
};
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 精灵按钮
class SpriteButton
: public Sprite
, public Button
{
public:
SpriteButton();
/// \~chinese
/// @brief 构造精灵按钮
/// @param click 按钮点击回调函数
explicit SpriteButton(Callback const& click);
/// \~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 构造精灵按钮
/// @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 文字按钮
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);
};
}
/// \~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

View File

@ -1,15 +1,15 @@
// 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
@ -24,330 +24,287 @@
namespace kiwano
{
Canvas::Canvas()
: cache_expired_(false)
, stroke_width_(1.0f)
, stroke_style_()
{
}
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;
}
}
}
Canvas::Canvas()
: cache_expired_(false)
, stroke_width_(1.0f)
, stroke_style_()
{
}
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

View File

@ -1,15 +1,15 @@
// 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
@ -20,315 +20,313 @@
#pragma once
#include <kiwano/2d/Actor.h>
#include <kiwano/render/RenderContext.h>
#include <kiwano/render/GeometrySink.h>
#include <kiwano/render/RenderContext.h>
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Canvas);
KGE_DECLARE_SMART_PTR(Canvas);
/**
* \addtogroup Actors
* @{
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Canvas
: public Actor
{
public:
/// \~chinese
/// @brief 构建空画布
Canvas();
/**
* \~chinese
* @brief
*/
class KGE_API Canvas : public Actor
{
public:
/// \~chinese
/// @brief 构建空画布
Canvas();
virtual ~Canvas();
virtual ~Canvas();
/// \~chinese
/// @brief 开始绘图
void BeginDraw();
/// \~chinese
/// @brief 开始绘图
void BeginDraw();
/// \~chinese
/// @brief 结束绘图
void EndDraw();
/// \~chinese
/// @brief 结束绘图
void EndDraw();
/// \~chinese
/// @brief 画线段
/// @param begin 线段起点
/// @param end 线段终点
void DrawLine(Point const& begin, Point const& end);
/// \~chinese
/// @brief 画线段
/// @param begin 线段起点
/// @param end 线段终点
void DrawLine(Point const& begin, Point const& end);
/// \~chinese
/// @brief 画圆形边框
/// @param center 圆形原点
/// @param radius 圆形半径
void DrawCircle(Point const& center, float radius);
/// \~chinese
/// @brief 画圆形边框
/// @param center 圆形原点
/// @param radius 圆形半径
void DrawCircle(Point const& center, float radius);
/// \~chinese
/// @brief 画椭圆形边框
/// @param center 椭圆原点
/// @param radius 椭圆半径
void DrawEllipse(Point const& center, Vec2 const& radius);
/// \~chinese
/// @brief 画椭圆形边框
/// @param center 椭圆原点
/// @param radius 椭圆半径
void DrawEllipse(Point const& center, Vec2 const& radius);
/// \~chinese
/// @brief 画矩形边框
/// @param rect 矩形
void DrawRect(Rect const& rect);
/// \~chinese
/// @brief 画矩形边框
/// @param rect 矩形
void DrawRect(Rect const& rect);
/// \~chinese
/// @brief 画圆角矩形边框
/// @param rect 矩形
/// @param radius 矩形圆角半径
void DrawRoundedRect(Rect const& rect, Vec2 const& radius);
/// \~chinese
/// @brief 画圆角矩形边框
/// @param rect 矩形
/// @param radius 矩形圆角半径
void DrawRoundedRect(Rect const& rect, Vec2 const& radius);
/// \~chinese
/// @brief 填充圆形
/// @param center 圆形原点
/// @param radius 圆形半径
void FillCircle(Point const& center, float radius);
/// \~chinese
/// @brief 填充圆形
/// @param center 圆形原点
/// @param radius 圆形半径
void FillCircle(Point const& center, float radius);
/// \~chinese
/// @brief 填充椭圆形
/// @param center 椭圆原点
/// @param radius 椭圆半径
void FillEllipse(Point const& center, Vec2 const& radius);
/// \~chinese
/// @brief 填充椭圆形
/// @param center 椭圆原点
/// @param radius 椭圆半径
void FillEllipse(Point const& center, Vec2 const& radius);
/// \~chinese
/// @brief 填充矩形
/// @param rect 矩形
void FillRect(Rect const& rect);
/// \~chinese
/// @brief 填充矩形
/// @param rect 矩形
void FillRect(Rect const& rect);
/// \~chinese
/// @brief 填充圆角矩形
/// @param rect 矩形
/// @param radius 矩形圆角半径
void FillRoundedRect(Rect const& rect, Vec2 const& radius);
/// \~chinese
/// @brief 填充圆角矩形
/// @param rect 矩形
/// @param radius 矩形圆角半径
void FillRoundedRect(Rect const& rect, Vec2 const& radius);
/// \~chinese
/// @brief 绘制纹理
/// @param texture 纹理
/// @param src_rect 纹理裁剪区域
/// @param dest_rect 绘制目标区域
void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
/// \~chinese
/// @brief 绘制纹理
/// @param texture 纹理
/// @param src_rect 纹理裁剪区域
/// @param dest_rect 绘制目标区域
void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr);
/// \~chinese
/// @brief 绘制文字布局
/// @param text 文字
/// @param point 绘制文字的位置
void DrawTextLayout(String const& text, Point const& point);
/// \~chinese
/// @brief 绘制文字布局
/// @param text 文字
/// @param point 绘制文字的位置
void DrawTextLayout(String const& text, Point const& point);
/// \~chinese
/// @brief 绘制文字布局
/// @param layout 文字布局
/// @param point 绘制布局的位置
void DrawTextLayout(TextLayout const& layout, Point const& point);
/// \~chinese
/// @brief 绘制文字布局
/// @param layout 文字布局
/// @param point 绘制布局的位置
void DrawTextLayout(TextLayout const& layout, Point const& point);
/// \~chinese
/// @brief 开始绘制路径
/// @param begin_pos 路径起始点
void BeginPath(Point const& begin_pos);
/// \~chinese
/// @brief 开始绘制路径
/// @param begin_pos 路径起始点
void BeginPath(Point const& begin_pos);
/// \~chinese
/// @brief 结束路径
/// @param closed 路径是否闭合
void EndPath(bool closed = false);
/// \~chinese
/// @brief 结束路径
/// @param closed 路径是否闭合
void EndPath(bool closed = false);
/// \~chinese
/// @brief 添加一条线段
/// @param point 端点
void AddLine(Point const& point);
/// \~chinese
/// @brief 添加一条线段
/// @param point 端点
void AddLine(Point const& point);
/// \~chinese
/// @brief 添加多条线段
/// @param points 端点集合
void AddLines(Vector<Point> const& points);
/// \~chinese
/// @brief 添加多条线段
/// @param points 端点集合
void AddLines(Vector<Point> const& points);
/// \~chinese
/// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
/// \~chinese
/// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
/// \~chinese
/// @brief 添加弧线
/// @param point 终点
/// @param radius 椭圆半径
/// @param rotation 椭圆旋转角度
/// @param clockwise 顺时针 or 逆时针
/// @param is_small 是否取小于 180° 的弧
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
/// \~chinese
/// @brief 添加弧线
/// @param point 终点
/// @param radius 椭圆半径
/// @param rotation 椭圆旋转角度
/// @param clockwise 顺时针 or 逆时针
/// @param is_small 是否取小于 180° 的弧
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
/// \~chinese
/// @brief 以描边的方式绘制路径
void StrokePath();
/// \~chinese
/// @brief 以描边的方式绘制路径
void StrokePath();
/// \~chinese
/// @brief 以填充的方式绘制路径
void FillPath();
/// \~chinese
/// @brief 以填充的方式绘制路径
void FillPath();
/// \~chinese
/// @brief 清空画布
void Clear();
/// \~chinese
/// @brief 清空画布
void Clear();
/// \~chinese
/// @brief 清空画布
/// @param clear_color 清空颜色
void Clear(Color const& clear_color);
/// \~chinese
/// @brief 清空画布
/// @param clear_color 清空颜色
void Clear(Color const& clear_color);
/// \~chinese
/// @brief 设置填充颜色
/// @param color 填充颜色
void SetFillColor(Color const& color);
/// \~chinese
/// @brief 设置填充颜色
/// @param color 填充颜色
void SetFillColor(Color const& color);
/// \~chinese
/// @brief 设置填充画刷
/// @param[in] brush 填充画刷
void SetFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置填充画刷
/// @param[in] brush 填充画刷
void SetFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置轮廓颜色
/// @param color 轮廓颜色
void SetStrokeColor(Color const& color);
/// \~chinese
/// @brief 设置轮廓颜色
/// @param color 轮廓颜色
void SetStrokeColor(Color const& color);
/// \~chinese
/// @brief 设置轮廓画刷
/// @param[in] brush 轮廓画刷
void SetStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置轮廓画刷
/// @param[in] brush 轮廓画刷
void SetStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置轮廓宽度
/// @param width 轮廓宽度
void SetStrokeWidth(float width);
/// \~chinese
/// @brief 设置轮廓宽度
/// @param width 轮廓宽度
void SetStrokeWidth(float width);
/// \~chinese
/// @brief 设置轮廓样式
/// @param stroke_style 轮廓样式
void SetStrokeStyle(const StrokeStyle& stroke_style);
/// \~chinese
/// @brief 设置轮廓样式
/// @param stroke_style 轮廓样式
void SetStrokeStyle(const StrokeStyle& stroke_style);
/// \~chinese
/// @brief 设置文字画刷样式
/// @param text_style 文字画刷样式
void SetTextStyle(TextStyle const& text_style);
/// \~chinese
/// @brief 设置文字画刷样式
/// @param text_style 文字画刷样式
void SetTextStyle(TextStyle const& text_style);
/// \~chinese
/// @brief 设置画刷
/// @param[in] brush 画刷
void SetBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置画刷
/// @param[in] brush 画刷
void SetBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置画刷二维变换
/// @param transform 二维变换
void SetBrushTransform(Transform const& transform);
/// \~chinese
/// @brief 设置画刷二维变换
/// @param transform 二维变换
void SetBrushTransform(Transform const& transform);
/// \~chinese
/// @brief 设置画刷二维变换矩阵
/// @param transform 二维变换矩阵
void SetBrushTransform(Matrix3x2 const& transform);
/// \~chinese
/// @brief 设置画刷二维变换矩阵
/// @param transform 二维变换矩阵
void SetBrushTransform(Matrix3x2 const& transform);
/// \~chinese
/// @brief 添加一个图层
/// @param area 图层区域
void PushLayerArea(LayerArea& area);
/// \~chinese
/// @brief 添加一个图层
/// @param area 图层区域
void PushLayerArea(LayerArea& area);
/// \~chinese
/// @brief 删除最近添加的图层
void PopLayerArea();
/// \~chinese
/// @brief 删除最近添加的图层
void PopLayerArea();
/// \~chinese
/// @brief 添加一个裁剪区域
/// @param clip_rect 裁剪矩形
void PushClipRect(Rect const& clip_rect);
/// \~chinese
/// @brief 添加一个裁剪区域
/// @param clip_rect 裁剪矩形
void PushClipRect(Rect const& clip_rect);
/// \~chinese
/// @brief 删除最近添加的裁剪区域
void PopClipRect();
/// \~chinese
/// @brief 删除最近添加的裁剪区域
void PopClipRect();
/// \~chinese
/// @brief 获取轮廓宽度
float GetStrokeWidth() const;
/// \~chinese
/// @brief 获取轮廓宽度
float GetStrokeWidth() const;
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const;
/// \~chinese
/// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const;
/// \~chinese
/// @brief 导出纹理
TexturePtr ExportToTexture() const;
/// \~chinese
/// @brief 导出纹理
TexturePtr ExportToTexture() const;
void OnRender(RenderContext& ctx) override;
void OnRender(RenderContext& ctx) override;
private:
void InitRenderTargetAndBrushs();
private:
void InitRenderTargetAndBrushs();
void UpdateCache() const;
void UpdateCache() const;
private:
float stroke_width_;
TextStyle text_style_;
StrokeStyle stroke_style_;
GeometrySink geo_sink_;
BrushPtr fill_brush_;
BrushPtr stroke_brush_;
private:
float stroke_width_;
TextStyle text_style_;
StrokeStyle stroke_style_;
GeometrySink geo_sink_;
BrushPtr fill_brush_;
BrushPtr stroke_brush_;
mutable bool cache_expired_;
mutable TexturePtr texture_cached_;
mutable TextureRenderContextPtr ctx_;
};
mutable bool cache_expired_;
mutable TexturePtr texture_cached_;
mutable TextureRenderContextPtr ctx_;
};
/** @} */
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_;
}
/** @} */
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

View File

@ -1,15 +1,15 @@
// 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
@ -19,129 +19,128 @@
// THE SOFTWARE.
#include <kiwano/2d/DebugActor.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/core/Logger.h>
#include <kiwano/render/Renderer.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
namespace kiwano
{
namespace
{
class comma_numpunct : public std::numpunct<wchar_t>
{
private:
virtual wchar_t do_thousands_sep() const override
{
return L',';
}
namespace
{
class comma_numpunct : public std::numpunct<wchar_t>
{
private:
virtual wchar_t do_thousands_sep() const override
{
return L',';
}
virtual std::string do_grouping() const override
{
return "\03";
}
};
}
virtual std::string do_grouping() const override
{
return "\03";
}
};
} // namespace
DebugActor::DebugActor()
{
SetName(L"kiwano-debug-actor");
SetPosition(Point{ 10, 10 });
SetResponsible(true);
SetCascadeOpacityEnabled(true);
DebugActor::DebugActor()
{
SetName(L"kiwano-debug-actor");
SetPosition(Point{ 10, 10 });
SetResponsible(true);
SetCascadeOpacityEnabled(true);
comma_locale_ = std::locale(std::locale(), new comma_numpunct);
comma_locale_ = std::locale(std::locale(), new comma_numpunct);
background_brush_ = new Brush;
background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f));
background_brush_ = new Brush;
background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f));
BrushPtr fill_brush = new Brush;
fill_brush->SetColor(Color::White);
BrushPtr fill_brush = new Brush;
fill_brush->SetColor(Color::White);
TextStyle style;
style.font_family = L"Arial";
style.font_size = 16.f;
style.font_weight = FontWeight::Normal;
style.line_spacing = 20.f;
style.fill_brush = fill_brush;
debug_text_.SetStyle(style);
TextStyle style;
style.font_family = L"Arial";
style.font_size = 16.f;
style.font_weight = FontWeight::Normal;
style.line_spacing = 20.f;
style.fill_brush = fill_brush;
debug_text_.SetStyle(style);
AddListener<MouseHoverEvent>([=](Event*) { SetOpacity(0.4f); });
AddListener<MouseOutEvent>([=](Event*) { SetOpacity(1.f); });
}
AddListener<MouseHoverEvent>([=](Event*) { SetOpacity(0.4f); });
AddListener<MouseOutEvent>([=](Event*) { SetOpacity(1.f); });
}
DebugActor::~DebugActor()
{
}
DebugActor::~DebugActor() {}
void DebugActor::OnRender(RenderContext& ctx)
{
ctx.SetCurrentBrush(background_brush_);
ctx.FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f });
ctx.DrawTextLayout(debug_text_, Point(10, 10));
}
void DebugActor::OnRender(RenderContext& ctx)
{
ctx.SetCurrentBrush(background_brush_);
ctx.FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f });
ctx.DrawTextLayout(debug_text_, Point(10, 10));
}
void DebugActor::OnUpdate(Duration dt)
{
KGE_NOT_USED(dt);
void DebugActor::OnUpdate(Duration dt)
{
KGE_NOT_USED(dt);
frame_time_.push_back(Time::Now());
while (frame_time_.back() - frame_time_.front() >= Duration::Second)
{
frame_time_.erase(frame_time_.begin());
}
frame_time_.push_back(Time::Now());
while (frame_time_.back() - frame_time_.front() >= Duration::Second)
{
frame_time_.erase(frame_time_.begin());
}
StringStream ss;
StringStream ss;
// For formatting integers with commas
(void)ss.imbue(comma_locale_);
// For formatting integers with commas
(void)ss.imbue(comma_locale_);
ss << "Fps: " << frame_time_.size() << std::endl;
ss << "Fps: " << frame_time_.size() << std::endl;
#if defined(KGE_DEBUG)
if (ObjectBase::IsTracingLeaks())
{
ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl;
}
if (ObjectBase::IsTracingLeaks())
{
ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl;
}
#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: ";
{
PROCESS_MEMORY_COUNTERS_EX pmc;
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
ss << "Memory: ";
{
PROCESS_MEMORY_COUNTERS_EX pmc;
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
if (pmc.PrivateUsage > 1024 * 1024)
{
ss << pmc.PrivateUsage / (1024 * 1024) << "Mb ";
pmc.PrivateUsage %= (1024 * 1024);
}
if (pmc.PrivateUsage > 1024 * 1024)
{
ss << pmc.PrivateUsage / (1024 * 1024) << "Mb ";
pmc.PrivateUsage %= (1024 * 1024);
}
ss << pmc.PrivateUsage / 1024 << "Kb";
}
ss << pmc.PrivateUsage / 1024 << "Kb";
}
debug_text_.SetText(ss.str());
debug_text_.Update();
debug_text_.SetText(ss.str());
debug_text_.Update();
Size layout_size = debug_text_.GetLayoutSize();
if (layout_size.x > GetWidth() - 20)
{
SetWidth(20 + layout_size.x);
}
if (layout_size.y > GetHeight() - 20)
{
SetHeight(20 + layout_size.y);
}
}
bool DebugActor::CheckVisibility(RenderContext& ctx) const
{
return true;
}
Size layout_size = debug_text_.GetLayoutSize();
if (layout_size.x > GetWidth() - 20)
{
SetWidth(20 + layout_size.x);
}
if (layout_size.y > GetHeight() - 20)
{
SetHeight(20 + layout_size.y);
}
}
bool DebugActor::CheckVisibility(RenderContext& ctx) const
{
return true;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -24,37 +24,35 @@
namespace kiwano
{
/**
* \addtogroup Actors
* @{
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief µ÷ÊÔ½Úµã
*/
class KGE_API DebugActor
: public Actor
{
public:
DebugActor();
/**
* \~chinese
* @brief µ÷ÊÔ½Úµã
*/
class KGE_API DebugActor : public Actor
{
public:
DebugActor();
virtual ~DebugActor();
virtual ~DebugActor();
void OnRender(RenderContext& ctx) override;
void OnRender(RenderContext& ctx) override;
void OnUpdate(Duration dt) override;
void OnUpdate(Duration dt) override;
protected:
bool CheckVisibility(RenderContext& ctx) const override;
protected:
bool CheckVisibility(RenderContext& ctx) const override;
private:
std::locale comma_locale_;
BrushPtr background_brush_;
TextLayout debug_text_;
Vector<Time> frame_time_;
};
private:
std::locale comma_locale_;
BrushPtr background_brush_;
TextLayout debug_text_;
Vector<Time> frame_time_;
};
/** @} */
}
/** @} */
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -23,52 +23,50 @@
namespace kiwano
{
Frame::Frame()
{
}
Frame::Frame() {}
bool Frame::Load(String const& file_path)
{
TexturePtr texture = TextureCache::Instance().AddOrGetTexture(file_path);
if (texture->IsValid())
{
SetTexture(texture);
return true;
}
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(String const& file_path)
{
TexturePtr texture = TextureCache::Instance().AddOrGetTexture(file_path);
if (texture->IsValid())
{
SetTexture(texture);
return true;
}
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();
}
}
} // namespace kiwano

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -23,79 +23,75 @@
namespace kiwano
{
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() {}
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

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -19,225 +19,226 @@
// THE SOFTWARE.
#include <kiwano/2d/GifSprite.h>
#include <kiwano/render/TextureCache.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/render/TextureCache.h>
namespace kiwano
{
GifSprite::GifSprite()
: animating_(false)
, next_index_(0)
, total_loop_count_(1)
, 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(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();
}
GifSprite::GifSprite()
: animating_(false)
, next_index_(0)
, total_loop_count_(1)
, 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(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

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -24,61 +24,59 @@
namespace kiwano
{
Layer::Layer()
: 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);
}
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;
}
Layer::Layer()
: 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);
}
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

View File

@ -1,15 +1,15 @@
// 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
@ -25,83 +25,93 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Layer);
KGE_DECLARE_SMART_PTR(Layer);
/**
* \addtogroup Actors
* @{
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Layer
: public Actor
{
public:
Layer();
/**
* \~chinese
* @brief
*/
class KGE_API Layer : public Actor
{
public:
Layer();
virtual ~Layer();
virtual ~Layer();
/// \~chinese
/// @brief 是否开启消息吞没
bool IsSwallowEventsEnabled() const;
/// \~chinese
/// @brief 是否开启消息吞没
bool IsSwallowEventsEnabled() const;
/// \~chinese
/// @brief 设置消息吞没功能
/// @param enabled 是否启用
void SetSwallowEvents(bool enabled);
/// \~chinese
/// @brief 设置消息吞没功能
/// @param enabled 是否启用
void SetSwallowEvents(bool enabled);
/// \~chinese
/// @brief 设置裁剪区域
/// @param clip_rect 裁剪矩形
void SetClipRect(Rect const& clip_rect);
/// \~chinese
/// @brief 设置裁剪区域
/// @param clip_rect 裁剪矩形
void SetClipRect(Rect const& clip_rect);
/// \~chinese
/// @brief 设置图层透明度
/// @param opacity 透明度
void SetOpacity(float opacity) override;
/// \~chinese
/// @brief 设置图层透明度
/// @param opacity 透明度
void SetOpacity(float opacity) override;
/// \~chinese
/// @brief 设置几何蒙层
/// @param mask 蒙层的几何形状
void SetMaskGeometry(Geometry const& mask);
/// \~chinese
/// @brief 设置几何蒙层
/// @param mask 蒙层的几何形状
void SetMaskGeometry(Geometry const& mask);
/// \~chinese
/// @brief 设置几何蒙层的二维变换
/// @param transform 应用于蒙层的二维变换
void SetMaskTransform(Matrix3x2 const& transform);
/// \~chinese
/// @brief 设置几何蒙层的二维变换
/// @param transform 应用于蒙层的二维变换
void SetMaskTransform(Matrix3x2 const& transform);
/// \~chinese
/// @brief 设置图层区域
/// @param area 图层区域属性
void SetArea(LayerArea const& area);
/// \~chinese
/// @brief 设置图层区域
/// @param area 图层区域属性
void SetArea(LayerArea const& area);
/// \~chinese
/// @brief 获取图层区域
LayerArea const& GetArea() const;
/// \~chinese
/// @brief 获取图层区域
LayerArea const& GetArea() const;
bool DispatchEvent(Event* evt) override;
bool DispatchEvent(Event* evt) override;
protected:
void Render(RenderContext& ctx) override;
protected:
void Render(RenderContext& ctx) override;
bool CheckVisibility(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
bool swallow_;
LayerArea area_;
};
private:
bool swallow_;
LayerArea area_;
};
/** @} */
inline bool Layer::IsSwallowEventsEnabled() const { return swallow_; }
inline void Layer::SetSwallowEvents(bool enabled) { swallow_ = enabled; }
inline void Layer::SetArea(LayerArea const& area) { area_ = area; }
inline LayerArea const& Layer::GetArea() const { return area_; }
/** @} */
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

View File

@ -1,15 +1,15 @@
// 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
@ -24,287 +24,248 @@
namespace kiwano
{
ShapeActor::ShapeActor()
: stroke_width_(1.f)
, 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(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());
}
ShapeActor::ShapeActor()
: stroke_width_(1.f)
, 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(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

View File

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

View File

@ -1,15 +1,15 @@
// 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
@ -23,64 +23,60 @@
namespace kiwano
{
Sprite::Sprite()
{
}
Sprite::Sprite() {}
Sprite::~Sprite()
{
}
Sprite::~Sprite() {}
bool Sprite::Load(String const& file_path)
{
FramePtr frame = new (std::nothrow) Frame;
if (frame->Load(file_path))
{
SetFrame(frame);
return true;
}
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(RenderContext& ctx)
{
ctx.DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
}
bool Sprite::CheckVisibility(RenderContext& ctx) const
{
return frame_ && frame_->IsValid() && Actor::CheckVisibility(ctx);
}
bool Sprite::Load(String const& file_path)
{
FramePtr frame = new (std::nothrow) Frame;
if (frame->Load(file_path))
{
SetFrame(frame);
return true;
}
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(RenderContext& ctx)
{
ctx.DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
}
bool Sprite::CheckVisibility(RenderContext& ctx) const
{
return frame_ && frame_->IsValid() && Actor::CheckVisibility(ctx);
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -24,60 +24,61 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Sprite);
KGE_DECLARE_SMART_PTR(Sprite);
/**
* \addtogroup Actors
* @{
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Sprite
: public Actor
{
public:
Sprite();
/**
* \~chinese
* @brief
*/
class KGE_API Sprite : public Actor
{
public:
Sprite();
virtual ~Sprite();
virtual ~Sprite();
/// \~chinese
/// @brief 加载本地图片
/// @param file_path 本地图片路径
bool Load(String const& file_path);
/// \~chinese
/// @brief 加载本地图片
/// @param file_path 本地图片路径
bool Load(String const& file_path);
/// \~chinese
/// @brief 加载图像资源
/// @param res 图片资源
bool Load(Resource const& res);
/// \~chinese
/// @brief 加载图像资源
/// @param res 图片资源
bool Load(Resource const& res);
/// \~chinese
/// @brief 使用矩形区域裁剪精灵
/// @param crop_rect 裁剪矩形
void SetCropRect(const Rect& crop_rect);
/// \~chinese
/// @brief 使用矩形区域裁剪精灵
/// @param crop_rect 裁剪矩形
void SetCropRect(const Rect& crop_rect);
/// \~chinese
/// @brief 获取帧图像
FramePtr GetFrame() const;
/// \~chinese
/// @brief 获取帧图像
FramePtr GetFrame() const;
/// \~chinese
/// @brief 设置图像帧
/// @param[in] frame 图像帧
void SetFrame(FramePtr frame);
/// \~chinese
/// @brief 设置图像帧
/// @param[in] frame 图像帧
void SetFrame(FramePtr frame);
void OnRender(RenderContext& ctx) override;
void OnRender(RenderContext& ctx) override;
protected:
bool CheckVisibility(RenderContext& ctx) const override;
protected:
bool CheckVisibility(RenderContext& ctx) const override;
private:
FramePtr frame_;
};
private:
FramePtr frame_;
};
/** @} */
inline FramePtr Sprite::GetFrame() const { return frame_; }
/** @} */
inline FramePtr Sprite::GetFrame() const
{
return frame_;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -24,45 +24,43 @@
namespace kiwano
{
Stage::Stage()
{
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(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);
}
Stage::Stage()
{
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(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

View File

@ -1,15 +1,15 @@
// 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
@ -24,86 +24,84 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Stage);
KGE_DECLARE_SMART_PTR(Stage);
/**
* \addtogroup Actors
* @{
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
* @details
* @see kiwano::Actor kiwano::Director
*/
class KGE_API Stage
: public Actor
{
friend class Transition;
friend class Director;
/**
* \~chinese
* @brief
* @details
* @see kiwano::Actor kiwano::Director
*/
class KGE_API Stage : public Actor
{
friend class Transition;
friend class Director;
public:
Stage();
public:
Stage();
virtual ~Stage();
virtual ~Stage();
/// \~chinese
/// @brief 进入舞台时
/// @details 重载该函数以处理进入舞台前的行为
virtual void OnEnter();
/// \~chinese
/// @brief 进入舞台时
/// @details 重载该函数以处理进入舞台前的行为
virtual void OnEnter();
/// \~chinese
/// @brief 退出舞台时
/// @details 重载该函数以处理退出舞台前的行为
virtual void OnExit();
/// \~chinese
/// @brief 退出舞台时
/// @details 重载该函数以处理退出舞台前的行为
virtual void OnExit();
/// \~chinese
/// @brief 获取角色边界填充画刷
BrushPtr GetBorderFillBrush() const;
/// \~chinese
/// @brief 获取角色边界填充画刷
BrushPtr GetBorderFillBrush() const;
/// \~chinese
/// @brief 获取角色边界轮廓画刷
BrushPtr GetBorderStrokeBrush() const;
/// \~chinese
/// @brief 获取角色边界轮廓画刷
BrushPtr GetBorderStrokeBrush() const;
/// \~chinese
/// @brief 设置角色边界填充画刷
void SetBorderFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置角色边界填充画刷
void SetBorderFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置角色边界轮廓画刷
void SetBorderStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置角色边界轮廓画刷
void SetBorderStrokeBrush(BrushPtr brush);
protected:
/// \~chinese
/// @brief 绘制所有子角色的边界
void RenderBorder(RenderContext& ctx) override;
protected:
/// \~chinese
/// @brief 绘制所有子角色的边界
void RenderBorder(RenderContext& ctx) override;
private:
BrushPtr border_fill_brush_;
BrushPtr border_stroke_brush_;
};
private:
BrushPtr border_fill_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

View File

@ -1,15 +1,15 @@
// 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
@ -24,111 +24,109 @@
namespace kiwano
{
namespace
{
TextStyle text_default_style;
namespace
{
TextStyle text_default_style;
void InitDefaultTextStyle()
{
static bool inited = false;
if (!inited)
{
inited = true;
// 默认使用白色画刷填充文字
text_default_style.fill_brush = new Brush;
text_default_style.fill_brush->SetColor(Color::White);
}
}
}
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);
}
void InitDefaultTextStyle()
{
static bool inited = false;
if (!inited)
{
inited = true;
// 默认使用白色画刷填充文字
text_default_style.fill_brush = new Brush;
text_default_style.fill_brush->SetColor(Color::White);
}
}
} // 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

View File

@ -1,15 +1,15 @@
// 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
@ -25,279 +25,277 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(TextActor);
KGE_DECLARE_SMART_PTR(TextActor);
/**
* \addtogroup Actors
* @{
*/
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API TextActor
: public Actor
{
public:
/// \~chinese
/// @brief 构建空的文本角色
TextActor();
/**
* \~chinese
* @brief
*/
class KGE_API TextActor : public Actor
{
public:
/// \~chinese
/// @brief 构建空的文本角色
TextActor();
/// \~chinese
/// @brief 构建文本角色
/// @param text 文字内容
explicit TextActor(const String& text);
/// \~chinese
/// @brief 构建文本角色
/// @param text 文字内容
explicit TextActor(const String& text);
/// \~chinese
/// @brief 构建文本角色
/// @param text 文字内容
/// @param style 文本样式
TextActor(const String& text, const TextStyle& style);
/// \~chinese
/// @brief 构建文本角色
/// @param text 文字内容
/// @param style 文本样式
TextActor(const String& text, const TextStyle& style);
virtual ~TextActor();
virtual ~TextActor();
/// \~chinese
/// @brief 获取文本
const String& GetText() const;
/// \~chinese
/// @brief 获取文本
const String& GetText() const;
/// \~chinese
/// @brief 获取文本样式
const TextStyle& GetStyle() const;
/// \~chinese
/// @brief 获取文本样式
const TextStyle& GetStyle() const;
/// \~chinese
/// @brief 获取文本布局
const TextLayout& GetLayout() const;
/// \~chinese
/// @brief 获取文本布局
const TextLayout& GetLayout() const;
/// \~chinese
/// @brief 获取文本布局大小
Size GetLayoutSize() const;
/// \~chinese
/// @brief 获取文本布局大小
Size GetLayoutSize() const;
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
/// \~chinese
/// @brief 获取描边画刷
BrushPtr GetOutlineBrush() const;
/// \~chinese
/// @brief 获取描边画刷
BrushPtr GetOutlineBrush() const;
/// \~chinese
/// @brief 获取字体
FontPtr GetFont() const;
/// \~chinese
/// @brief 获取字体
FontPtr GetFont() const;
/// \~chinese
/// @brief 设置文本
void SetText(String const& text);
/// \~chinese
/// @brief 设置文本
void SetText(String const& text);
/// \~chinese
/// @brief 设置文本样式
void SetStyle(const TextStyle& style);
/// \~chinese
/// @brief 设置文本样式
void SetStyle(const TextStyle& style);
/// \~chinese
/// @brief 设置字体
void SetFont(FontPtr font);
/// \~chinese
/// @brief 设置字体
void SetFont(FontPtr font);
/// \~chinese
/// @brief 设置字体族
void SetFontFamily(String const& family);
/// \~chinese
/// @brief 设置字体族
void SetFontFamily(String const& family);
/// \~chinese
/// @brief 设置字号(默认值为 18
void SetFontSize(float size);
/// \~chinese
/// @brief 设置字号(默认值为 18
void SetFontSize(float size);
/// \~chinese
/// @brief 设置字体粗细值(默认值为 FontWeight::Normal
void SetFontWeight(uint32_t weight);
/// \~chinese
/// @brief 设置字体粗细值(默认值为 FontWeight::Normal
void SetFontWeight(uint32_t weight);
/// \~chinese
/// @brief 设置文字填充画刷
void SetFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字填充画刷
void SetFillBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字填充颜色(默认值为 Color::White
void SetFillColor(Color const& color);
/// \~chinese
/// @brief 设置文字填充颜色(默认值为 Color::White
void SetFillColor(Color const& color);
/// \~chinese
/// @brief 设置文字斜体(默认值为 false
void SetItalic(bool italic);
/// \~chinese
/// @brief 设置文字斜体(默认值为 false
void SetItalic(bool italic);
/// \~chinese
/// @brief 设置文本自动换行的宽度(默认为 0
void SetWrapWidth(float wrap_width);
/// \~chinese
/// @brief 设置文本自动换行的宽度(默认为 0
void SetWrapWidth(float wrap_width);
/// \~chinese
/// @brief 设置行间距(默认为 0
void SetLineSpacing(float line_spacing);
/// \~chinese
/// @brief 设置行间距(默认为 0
void SetLineSpacing(float line_spacing);
/// \~chinese
/// @brief 设置对齐方式(默认为 TextAlign::Left
void SetAlignment(TextAlign align);
/// \~chinese
/// @brief 设置对齐方式(默认为 TextAlign::Left
void SetAlignment(TextAlign align);
/// \~chinese
/// @brief 设置文字描边画刷
void SetOutlineBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字描边画刷
void SetOutlineBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置文字描边颜色
void SetOutlineColor(Color const& outline_color);
/// \~chinese
/// @brief 设置文字描边颜色
void SetOutlineColor(Color const& outline_color);
/// \~chinese
/// @brief 设置文字描边线宽
void SetOutlineWidth(float outline_width);
/// \~chinese
/// @brief 设置文字描边线宽
void SetOutlineWidth(float outline_width);
/// \~chinese
/// @brief 设置文字描边线相交样式
void SetOutlineStroke(const StrokeStyle& outline_stroke);
/// \~chinese
/// @brief 设置文字描边线相交样式
void SetOutlineStroke(const StrokeStyle& outline_stroke);
/// \~chinese
/// @brief 设置是否显示下划线(默认值为 false
void SetUnderline(bool enable);
/// \~chinese
/// @brief 设置是否显示下划线(默认值为 false
void SetUnderline(bool enable);
/// \~chinese
/// @brief 设置是否显示删除线(默认值为 false
void SetStrikethrough(bool enable);
/// \~chinese
/// @brief 设置是否显示删除线(默认值为 false
void SetStrikethrough(bool enable);
/// \~chinese
/// @brief 更新文字布局
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
void UpdateLayout();
/// \~chinese
/// @brief 更新文字布局
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
void UpdateLayout();
/// \~chinese
/// @brief 设置默认文字样式
static void SetDefaultStyle(TextStyle const& style);
/// \~chinese
/// @brief 设置默认文字样式
static void SetDefaultStyle(TextStyle const& style);
/// \~chinese
/// @brief 获取默认文字样式
static const TextStyle& GetDefaultStyle();
/// \~chinese
/// @brief 获取默认文字样式
static const TextStyle& GetDefaultStyle();
void OnRender(RenderContext& ctx) override;
void OnRender(RenderContext& ctx) override;
void OnUpdate(Duration dt) override;
void OnUpdate(Duration dt) override;
protected:
bool CheckVisibility(RenderContext& ctx) const override;
protected:
bool CheckVisibility(RenderContext& ctx) const override;
private:
bool show_underline_;
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 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);
}
/** @} */
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

View File

@ -1,15 +1,15 @@
// 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
@ -22,28 +22,25 @@
namespace kiwano
{
Transform::Transform()
: position()
, rotation(0.f)
, scale(1.f, 1.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;
}
Transform::Transform()
: position()
, rotation(0.f)
, scale(1.f, 1.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;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -23,25 +23,25 @@
namespace kiwano
{
/**
* \~chinese
* @brief
*/
class Transform
{
public:
float rotation; ///< 旋转
Point position; ///< 坐标
Point scale; ///< 缩放
Point skew; ///< 错切角度
/**
* \~chinese
* @brief
*/
class Transform
{
public:
float rotation; ///< 旋转
Point position; ///< 坐标
Point scale; ///< 缩放
Point skew; ///< 错切角度
public:
Transform();
public:
Transform();
/// \~chinese
/// @brief 将二维放射变换转换为矩阵
Matrix3x2 ToMatrix() const;
/// \~chinese
/// @brief 将二维放射变换转换为矩阵
Matrix3x2 ToMatrix() const;
bool operator== (const Transform& rhs) const;
};
}
bool operator==(const Transform& rhs) const;
};
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,369 +18,355 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/2d/Transition.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/Stage.h>
#include <kiwano/platform/Window.h>
#include <kiwano/2d/Transition.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/Window.h>
#include <kiwano/render/Renderer.h>
namespace kiwano
{
//-------------------------------------------------------
// Transition
//-------------------------------------------------------
//-------------------------------------------------------
// Transition
//-------------------------------------------------------
Transition::Transition(Duration duration)
: done_(false)
, duration_(duration)
, delta_()
, process_(0)
, window_size_()
, out_stage_(nullptr)
, in_stage_(nullptr)
, out_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(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 });
}
}
Transition::Transition(Duration duration)
: done_(false)
, duration_(duration)
, delta_()
, process_(0)
, window_size_()
, out_stage_(nullptr)
, in_stage_(nullptr)
, out_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(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

View File

@ -1,15 +1,15 @@
// 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
@ -24,258 +24,215 @@
namespace kiwano
{
class Director;
class RenderContext;
class Director;
class RenderContext;
KGE_DECLARE_SMART_PTR(Transition);
KGE_DECLARE_SMART_PTR(FadeTransition);
KGE_DECLARE_SMART_PTR(EmergeTransition);
KGE_DECLARE_SMART_PTR(BoxTransition);
KGE_DECLARE_SMART_PTR(MoveTransition);
KGE_DECLARE_SMART_PTR(RotationTransition);
KGE_DECLARE_SMART_PTR(Transition);
KGE_DECLARE_SMART_PTR(FadeTransition);
KGE_DECLARE_SMART_PTR(EmergeTransition);
KGE_DECLARE_SMART_PTR(BoxTransition);
KGE_DECLARE_SMART_PTR(MoveTransition);
KGE_DECLARE_SMART_PTR(RotationTransition);
/**
* \~chinese
* @brief
*/
class KGE_API Transition
: public virtual ObjectBase
{
friend class Director;
/**
* \~chinese
* @brief
*/
class KGE_API Transition : public virtual ObjectBase
{
friend class Director;
public:
/**
* \~chinese
* @brief
* @param duration
*/
explicit Transition(
Duration duration
);
public:
/**
* \~chinese
* @brief
* @param duration
*/
explicit Transition(Duration duration);
virtual ~Transition();
virtual ~Transition();
/**
* \~chinese
* @brief
*/
bool IsDone();
/**
* \~chinese
* @brief
*/
bool IsDone();
protected:
/**
* \~chinese
* @brief
* @param[in] prev
* @param[in] next
*/
virtual void Init(
StagePtr prev,
StagePtr next
);
protected:
/**
* \~chinese
* @brief
* @param[in] prev
* @param[in] next
*/
virtual void Init(StagePtr prev, StagePtr next);
/**
* \~chinese
* @brief
* @param dt
*/
virtual void Update(Duration dt);
/**
* \~chinese
* @brief
* @param dt
*/
virtual void Update(Duration dt);
/**
* \~chinese
* @brief
* @param[in] ctx
*/
virtual void Render(RenderContext& ctx);
/**
* \~chinese
* @brief
* @param[in] ctx
*/
virtual void Render(RenderContext& ctx);
/**
* \~chinese
* @brief
*/
virtual void Stop();
/**
* \~chinese
* @brief
*/
virtual void Stop();
/**
* \~chinese
* @brief
*/
virtual void Reset() {}
/**
* \~chinese
* @brief
*/
virtual void Reset() {}
protected:
bool done_;
float process_;
Duration duration_;
Duration delta_;
Size window_size_;
StagePtr out_stage_;
StagePtr in_stage_;
LayerArea out_layer_;
LayerArea in_layer_;
};
protected:
bool done_;
float process_;
Duration duration_;
Duration delta_;
Size window_size_;
StagePtr out_stage_;
StagePtr in_stage_;
LayerArea out_layer_;
LayerArea in_layer_;
};
/**
* \~chinese
* @brief
* @details
*/
class FadeTransition : public Transition
{
public:
/**
* \~chinese
* @brief
* @param duration
*/
explicit FadeTransition(Duration duration);
/**
* \~chinese
* @brief
* @details
*/
class FadeTransition
: public Transition
{
public:
/**
* \~chinese
* @brief
* @param duration
*/
explicit FadeTransition(
Duration duration
);
protected:
void Update(Duration dt) override;
protected:
void Update(Duration dt) override;
virtual void Init(StagePtr prev, StagePtr next) 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 EmergeTransition
: public Transition
{
public:
/**
* \~chinese
* @brief
* @param duration
*/
explicit EmergeTransition(
Duration duration
);
virtual void Init(StagePtr prev, StagePtr next) override;
};
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(
StagePtr prev,
StagePtr next
) override;
};
protected:
void Update(Duration dt) override;
virtual void Init(StagePtr prev, StagePtr next) override;
};
/**
* \~chinese
* @brief
* @details
*/
class BoxTransition
: public Transition
{
public:
/**
* \~chinese
* @brief
* @param duration
*/
explicit BoxTransition(
Duration duration
);
/**
* \~chinese
* @brief
* @details
*/
class MoveTransition : public Transition
{
public:
/**
* \~chinese
* @brief
*/
enum class Type : int
{
Up, ///< 上移
Down, ///< 下移
Left, ///< 左移
Right ///< 右移
};
protected:
void Update(Duration dt) override;
/**
* \~chinese
* @brief
* @param duration
* @param type
*/
explicit MoveTransition(Duration duration, Type type);
virtual void Init(
StagePtr prev,
StagePtr next
) override;
};
protected:
void Update(Duration dt) override;
virtual void Init(StagePtr prev, StagePtr next) override;
/**
* \~chinese
* @brief
* @details
*/
class MoveTransition
: public Transition
{
public:
/**
* \~chinese
* @brief
*/
enum class Type : int
{
Up, ///< 上移
Down, ///< 下移
Left, ///< 左移
Right ///< 右移
};
void Reset() override;
/**
* \~chinese
* @brief
* @param duration
* @param type
*/
explicit MoveTransition(
Duration duration,
Type type
);
private:
Type type_;
Point pos_delta_;
Point start_pos_;
};
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(
StagePtr prev,
StagePtr next
) override;
protected:
void Update(Duration dt) override;
void Reset() override;
virtual void Init(StagePtr prev, StagePtr next) override;
private:
Type type_;
Point pos_delta_;
Point start_pos_;
};
void Reset() override;
/**
* \~chinese
* @brief
* @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_;
};
}
private:
float rotation_;
};
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,96 +18,91 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/2d/action/Action.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/action/Action.h>
namespace kiwano
{
Action::Action()
: running_(true)
, detach_target_(false)
, loops_done_(0)
, loops_(0)
, 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()
: running_(true)
, detach_target_(false)
, loops_done_(0)
, loops_(0)
, 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);
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -20,271 +20,270 @@
#pragma once
#include <kiwano/core/Common.h>
#include <kiwano/core/Time.h>
#include <kiwano/core/SmartPtr.hpp>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/SmartPtr.hpp>
#include <kiwano/core/Time.h>
#include <kiwano/math/math.h>
namespace kiwano
{
class Actor;
class ActionManager;
class Actor;
class ActionManager;
KGE_DECLARE_SMART_PTR(Action);
KGE_DECLARE_SMART_PTR(Action);
/**
* \~chinese
* \defgroup Actions
*/
/**
* \~chinese
* \defgroup Actions
*/
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 动画
class KGE_API Action
: public virtual ObjectBase
, protected IntrusiveListItem<ActionPtr>
{
friend class ActionManager;
friend class ActionGroup;
friend IntrusiveList<ActionPtr>;
/// \~chinese
/// @brief 动画
class KGE_API Action
: public virtual ObjectBase
, protected IntrusiveListItem<ActionPtr>
{
friend class ActionManager;
friend class ActionGroup;
friend IntrusiveList<ActionPtr>;
public:
/// \~chinese
/// @brief 动画结束时的回调函数
using DoneCallback = Function<void(Actor* /* target */)>;
public:
/// \~chinese
/// @brief 动画结束时的回调函数
using DoneCallback = Function<void(Actor* /* target */)>;
Action();
Action();
virtual ~Action();
virtual ~Action();
/// \~chinese
/// @brief 继续动画
void Resume();
/// \~chinese
/// @brief 继续动画
void Resume();
/// \~chinese
/// @brief 暂停动画
void Pause();
/// \~chinese
/// @brief 暂停动画
void Pause();
/// \~chinese
/// @brief 停止动画
void Stop();
/// \~chinese
/// @brief 停止动画
void Stop();
/// \~chinese
/// @brief 设置动画延时
void SetDelay(Duration delay);
/// \~chinese
/// @brief 设置动画延时
void SetDelay(Duration delay);
/// \~chinese
/// @brief 设置循环次数
/// @param loops 循环次数,-1 为永久循环
void SetLoops(int loops);
/// \~chinese
/// @brief 设置循环次数
/// @param loops 循环次数,-1 为永久循环
void SetLoops(int loops);
/// \~chinese
/// @brief 动画结束时移除目标角色
void RemoveTargetWhenDone();
/// \~chinese
/// @brief 动画结束时移除目标角色
void RemoveTargetWhenDone();
/// \~chinese
/// @brief 设置动画结束时的回调函数
void SetDoneCallback(DoneCallback const& cb);
/// \~chinese
/// @brief 设置动画结束时的回调函数
void SetDoneCallback(DoneCallback const& cb);
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
void SetLoopDoneCallback(DoneCallback const& cb);
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
void SetLoopDoneCallback(DoneCallback const& cb);
/// \~chinese
/// @brief 获取动画的拷贝
virtual ActionPtr Clone() const = 0;
/// \~chinese
/// @brief 获取动画的拷贝
virtual ActionPtr Clone() const = 0;
/// \~chinese
/// @brief 获取动画的倒转
virtual ActionPtr Reverse() const = 0;
/// \~chinese
/// @brief 获取动画的倒转
virtual ActionPtr Reverse() const = 0;
/// \~chinese
/// @brief 获取动画的运行状态
bool IsRunning() const;
/// \~chinese
/// @brief 获取动画的运行状态
bool IsRunning() const;
/// \~chinese
/// @brief 获取动画的循环次数
int GetLoops() const;
/// \~chinese
/// @brief 获取动画的循环次数
int GetLoops() const;
/// \~chinese
/// @brief 获取动画的延时
Duration GetDelay() const;
/// \~chinese
/// @brief 获取动画的延时
Duration GetDelay() const;
/// \~chinese
/// @brief 获取动画结束时的回调函数
DoneCallback GetDoneCallback() const;
/// \~chinese
/// @brief 获取动画结束时的回调函数
DoneCallback GetDoneCallback() const;
/// \~chinese
/// @brief 获取动画循环结束时的回调函数
DoneCallback GetLoopDoneCallback() const;
/// \~chinese
/// @brief 获取动画循环结束时的回调函数
DoneCallback GetLoopDoneCallback() const;
protected:
/// \~chinese
/// @brief 初始化动画
virtual void Init(Actor* target);
protected:
/// \~chinese
/// @brief 初始化动画
virtual void Init(Actor* target);
/// \~chinese
/// @brief 更新动画
virtual void Update(Actor* target, Duration dt);
/// \~chinese
/// @brief 更新动画
virtual void Update(Actor* target, Duration dt);
/// \~chinese
/// @brief 更新一个时间步
void UpdateStep(Actor* target, Duration dt);
/// \~chinese
/// @brief 更新一个时间步
void UpdateStep(Actor* target, Duration dt);
/// \~chinese
/// @brief 完成动画
void Complete(Actor* target);
/// \~chinese
/// @brief 完成动画
void Complete(Actor* target);
/// \~chinese
/// @brief 重新开始动画
void Restart(Actor* target);
/// \~chinese
/// @brief 重新开始动画
void Restart(Actor* target);
/// \~chinese
/// @brief 动画状态
enum class Status
{
NotStarted, ///< 未开始
Delayed, ///< 等待延时
Started, ///< 已开始
Done, ///< 已结束
Removeable ///< 可移除
};
/// \~chinese
/// @brief 动画状态
enum class Status
{
NotStarted, ///< 未开始
Delayed, ///< 等待延时
Started, ///< 已开始
Done, ///< 已结束
Removeable ///< 可移除
};
/// \~chinese
/// @brief 获取动画状态
Status GetStatus() const;
/// \~chinese
/// @brief 获取动画状态
Status GetStatus() const;
/// \~chinese
/// @brief 获取消逝时间
Duration GetElapsed() const;
/// \~chinese
/// @brief 获取消逝时间
Duration GetElapsed() const;
/// \~chinese
/// @brief 获取完成的循环次数
int GetLoopsDone() const;
/// \~chinese
/// @brief 获取完成的循环次数
int GetLoopsDone() const;
/// \~chinese
/// @brief 结束动画
void Done();
/// \~chinese
/// @brief 结束动画
void Done();
/// \~chinese
/// @brief 是否已结束
bool IsDone() const;
/// \~chinese
/// @brief 是否已结束
bool IsDone() const;
/// \~chinese
/// @brief 是否可移除
bool IsRemoveable() const;
/// \~chinese
/// @brief 是否可移除
bool IsRemoveable() const;
private:
Status status_;
bool running_;
bool detach_target_;
int loops_;
int loops_done_;
Duration delay_;
Duration elapsed_;
DoneCallback cb_done_;
DoneCallback cb_loop_done_;
};
private:
Status status_;
bool running_;
bool detach_target_;
int loops_;
int loops_done_;
Duration delay_;
Duration elapsed_;
DoneCallback cb_done_;
DoneCallback cb_loop_done_;
};
/** @} */
/** @} */
inline void Action::Resume()
{
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::Resume()
{
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_;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -22,19 +22,19 @@
namespace kiwano
{
ActionDelay::ActionDelay(Duration delay)
{
SetDelay(delay);
}
ActionPtr ActionDelay::Clone() const
{
return new ActionDelay(GetDelay());
}
ActionPtr ActionDelay::Reverse() const
{
return new ActionDelay(GetDelay());
}
ActionDelay::ActionDelay(Duration delay)
{
SetDelay(delay);
}
ActionPtr ActionDelay::Clone() const
{
return new ActionDelay(GetDelay());
}
ActionPtr ActionDelay::Reverse() const
{
return new ActionDelay(GetDelay());
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -23,32 +23,29 @@
namespace kiwano
{
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 延时动画
class KGE_API ActionDelay
: public Action
{
public:
/// \~chinese
/// @brief 构建延时动画
/// @param delay 延时时长
ActionDelay(
Duration delay
);
/// \~chinese
/// @brief 延时动画
class KGE_API ActionDelay : public Action
{
public:
/// \~chinese
/// @brief 构建延时动画
/// @param delay 延时时长
ActionDelay(Duration delay);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
};
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
};
/** @} */
}
/** @} */
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,131 +18,129 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/2d/action/ActionGroup.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/action/ActionGroup.h>
#include <kiwano/core/Logger.h>
namespace kiwano
{
//-------------------------------------------------------
// 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::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

View File

@ -1,15 +1,15 @@
// 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
@ -23,66 +23,68 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(ActionGroup);
KGE_DECLARE_SMART_PTR(ActionGroup);
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 动画组合
class KGE_API ActionGroup
: public Action
{
public:
using ActionList = IntrusiveList<ActionPtr>;
/// \~chinese
/// @brief 动画组合
class KGE_API ActionGroup : public Action
{
public:
using ActionList = IntrusiveList<ActionPtr>;
ActionGroup();
ActionGroup();
/// \~chinese
/// @brief 动画组合
/// @param actions 动画集合
/// @param sequence 动画按顺序依次执行或同时执行
explicit ActionGroup(Vector<ActionPtr> const& actions, bool sequence = true);
/// \~chinese
/// @brief 动画组合
/// @param actions 动画集合
/// @param sequence 动画按顺序依次执行或同时执行
explicit ActionGroup(Vector<ActionPtr> const& actions, bool sequence = true);
virtual ~ActionGroup();
virtual ~ActionGroup();
/// \~chinese
/// @brief 添加动画
/// @param action 动画
void Add(ActionPtr action);
/// \~chinese
/// @brief 添加动画
/// @param action 动画
void Add(ActionPtr action);
/// \~chinese
/// @brief 添加多个动画
/// @param actions 动画集合
void Add(Vector<ActionPtr> const& actions);
/// \~chinese
/// @brief 添加多个动画
/// @param actions 动画集合
void Add(Vector<ActionPtr> const& actions);
/// \~chinese
/// @brief 获取所有动画
ActionList const& GetActions() const;
/// \~chinese
/// @brief 获取所有动画
ActionList const& GetActions() const;
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
protected:
void Init(Actor* target) override;
void Update(Actor* target, Duration dt) override;
void Update(Actor* target, Duration dt) override;
private:
bool sequence_;
ActionPtr current_;
ActionList actions_;
};
private:
bool sequence_;
ActionPtr current_;
ActionList actions_;
};
/** @} */
inline ActionGroup::ActionList const& ActionGroup::GetActions() const { return actions_; }
/** @} */
inline ActionGroup::ActionList const& ActionGroup::GetActions() const
{
return actions_;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,293 +19,354 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/2d/action/ActionTween.h>
#include <kiwano/2d/action/ActionWalk.h>
#include <kiwano/2d/action/ActionDelay.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>
namespace kiwano
{
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 动画辅助类
struct ActionHelper
{
using DoneCallback = Action::DoneCallback;
/// \~chinese
/// @brief 动画辅助类
struct ActionHelper
{
using DoneCallback = Action::DoneCallback;
/// \~chinese
/// @brief 设置循环次数
inline ActionHelper& SetLoops(int loops) { core->SetLoops(loops); return (*this); }
/// \~chinese
/// @brief 设置循环次数
inline ActionHelper& SetLoops(int loops)
{
core->SetLoops(loops);
return (*this);
}
/// \~chinese
/// @brief 设置动画延迟
inline ActionHelper& SetDelay(Duration delay) { core->SetDelay(delay); return (*this); }
/// \~chinese
/// @brief 设置动画延迟
inline ActionHelper& SetDelay(Duration delay)
{
core->SetDelay(delay);
return (*this);
}
/// \~chinese
/// @brief 设置动画结束回调函数
inline ActionHelper& SetDoneCallback(DoneCallback const& cb) { core->SetDoneCallback(cb); return (*this); }
/// \~chinese
/// @brief 设置动画结束回调函数
inline ActionHelper& SetDoneCallback(DoneCallback const& cb)
{
core->SetDoneCallback(cb);
return (*this);
}
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
inline ActionHelper& SetLoopDoneCallback(DoneCallback const& cb) { core->SetLoopDoneCallback(cb); return (*this); }
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
inline ActionHelper& SetLoopDoneCallback(DoneCallback const& cb)
{
core->SetLoopDoneCallback(cb);
return (*this);
}
/// \~chinese
/// @brief 动画结束时移除目标角色
inline ActionHelper& RemoveTargetWhenDone() { core->RemoveTargetWhenDone(); return (*this); }
/// \~chinese
/// @brief 动画结束时移除目标角色
inline ActionHelper& RemoveTargetWhenDone()
{
core->RemoveTargetWhenDone();
return (*this);
}
/// \~chinese
/// @brief 设置名称
inline ActionHelper& SetName(String const& name) { core->SetName(name); return (*this); }
/// \~chinese
/// @brief 设置名称
inline ActionHelper& SetName(String const& name)
{
core->SetName(name);
return (*this);
}
/// \~chinese
/// @brief 获取指针
inline ActionPtr Get() const { return core; }
/// \~chinese
/// @brief 获取指针
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:
ActionPtr core;
};
private:
ActionPtr core;
};
/// \~chinese
/// @brief 补间动画辅助类
struct TweenHelper
{
using DoneCallback = Action::DoneCallback;
/// \~chinese
/// @brief 补间动画辅助类
struct TweenHelper
{
using DoneCallback = Action::DoneCallback;
/// \~chinese
/// @brief 设置动画持续时长
inline TweenHelper& SetDuration(Duration dur) { core->SetDuration(dur); return (*this); }
/// \~chinese
/// @brief 设置动画持续时长
inline TweenHelper& SetDuration(Duration dur)
{
core->SetDuration(dur);
return (*this);
}
/// \~chinese
/// @brief 设置循环次数
inline TweenHelper& SetLoops(int loops) { core->SetLoops(loops); return (*this); }
/// \~chinese
/// @brief 设置循环次数
inline TweenHelper& SetLoops(int loops)
{
core->SetLoops(loops);
return (*this);
}
/// \~chinese
/// @brief 设置缓动函数
inline TweenHelper& SetEaseFunc(EaseFunc ease) { core->SetEaseFunc(ease); return (*this); }
/// \~chinese
/// @brief 设置缓动函数
inline TweenHelper& SetEaseFunc(EaseFunc ease)
{
core->SetEaseFunc(ease);
return (*this);
}
/// \~chinese
/// @brief 设置动画延迟
inline TweenHelper& SetDelay(Duration delay) { core->SetDelay(delay); return (*this); }
/// \~chinese
/// @brief 设置动画延迟
inline TweenHelper& SetDelay(Duration delay)
{
core->SetDelay(delay);
return (*this);
}
/// \~chinese
/// @brief 设置动画结束回调函数
inline TweenHelper& SetDoneCallback(DoneCallback const& cb) { core->SetDoneCallback(cb); return (*this); }
/// \~chinese
/// @brief 设置动画结束回调函数
inline TweenHelper& SetDoneCallback(DoneCallback const& cb)
{
core->SetDoneCallback(cb);
return (*this);
}
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
inline TweenHelper& SetLoopDoneCallback(DoneCallback const& cb) { core->SetLoopDoneCallback(cb); return (*this); }
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
inline TweenHelper& SetLoopDoneCallback(DoneCallback const& cb)
{
core->SetLoopDoneCallback(cb);
return (*this);
}
/// \~chinese
/// @brief 动画结束时移除目标角色
inline TweenHelper& RemoveTargetWhenDone() { core->RemoveTargetWhenDone(); return (*this); }
/// \~chinese
/// @brief 动画结束时移除目标角色
inline TweenHelper& RemoveTargetWhenDone()
{
core->RemoveTargetWhenDone();
return (*this);
}
/// \~chinese
/// @brief 设置名称
inline TweenHelper& SetName(String const& name) { core->SetName(name); return (*this); }
/// \~chinese
/// @brief 设置名称
inline TweenHelper& SetName(String const& name)
{
core->SetName(name);
return (*this);
}
/// \~chinese
/// @brief 获取指针
inline ActionTweenPtr Get() const { return core; }
inline TweenHelper(ActionTweenPtr core) : core(core) {}
/// \~chinese
/// @brief 获取指针
inline ActionTweenPtr Get() const
{
return core;
}
inline operator ActionPtr() const { return core; }
inline TweenHelper(ActionTweenPtr core)
: core(core)
{
}
inline operator ActionTweenPtr() const { return core; }
inline operator ActionPtr() const
{
return core;
}
private:
ActionTweenPtr core;
};
inline operator ActionTweenPtr() const
{
return core;
}
/// \~chinese
/// @brief 动画构造器
struct Tween
{
public:
/// \~chinese
/// @brief 构造相对位移动画
/// @param duration 动画时长
/// @param vector 移动向量
static inline TweenHelper
MoveBy(Duration dur, Point const& vector)
{
return TweenHelper(new kiwano::ActionMoveBy(dur, vector));
}
private:
ActionTweenPtr core;
};
/// \~chinese
/// @brief 构造位移动画
/// @param duration 动画时长
/// @param pos 目的坐标
static inline TweenHelper
MoveTo(Duration dur, Point const& pos)
{
return TweenHelper(new kiwano::ActionMoveTo(dur, pos));
}
/// \~chinese
/// @brief 动画构造器
struct Tween
{
public:
/// \~chinese
/// @brief 构造相对位移动画
/// @param duration 动画时长
/// @param vector 移动向量
static inline TweenHelper MoveBy(Duration dur, Point const& vector)
{
return TweenHelper(new kiwano::ActionMoveBy(dur, vector));
}
/// \~chinese
/// @brief 构造相对跳跃动画
/// @param duration 动画时长
/// @param vec 跳跃位移向量
/// @param height 跳跃高度
/// @param jumps 跳跃次数
static inline TweenHelper
JumpBy(Duration duration, Vec2 const& vec, float height, int jumps = 1)
{
return TweenHelper(new kiwano::ActionJumpBy(duration, vec, height, jumps));
}
/// \~chinese
/// @brief 构造位移动画
/// @param duration 动画时长
/// @param pos 目的坐标
static inline TweenHelper MoveTo(Duration dur, Point const& pos)
{
return TweenHelper(new kiwano::ActionMoveTo(dur, pos));
}
/// \~chinese
/// @brief 构造跳跃动画
/// @param duration 动画时长
/// @param pos 目的坐标
/// @param height 跳跃高度
/// @param jumps 跳跃次数
static inline TweenHelper
JumpTo(Duration duration, Point const& pos, float height, int jumps = 1)
{
return TweenHelper(new kiwano::ActionJumpTo(duration, pos, height, jumps));
}
/// \~chinese
/// @brief 构造相对跳跃动画
/// @param duration 动画时长
/// @param vec 跳跃位移向量
/// @param height 跳跃高度
/// @param jumps 跳跃次数
static inline TweenHelper JumpBy(Duration duration, Vec2 const& vec, float height, int jumps = 1)
{
return TweenHelper(new kiwano::ActionJumpBy(duration, vec, height, jumps));
}
/// \~chinese
/// @brief 构造相对缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放相对变化值
/// @param scale_y 纵向缩放相对变化值
static inline TweenHelper
ScaleBy(Duration dur, float scale_x, float scale_y)
{
return TweenHelper(new kiwano::ActionScaleBy(dur, scale_x, scale_y));
}
/// \~chinese
/// @brief 构造跳跃动画
/// @param duration 动画时长
/// @param pos 目的坐标
/// @param height 跳跃高度
/// @param jumps 跳跃次数
static inline TweenHelper JumpTo(Duration duration, Point const& pos, float height, int jumps = 1)
{
return TweenHelper(new kiwano::ActionJumpTo(duration, pos, height, jumps));
}
/// \~chinese
/// @brief 构造缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放目标值
/// @param scale_y 纵向缩放目标值
static inline TweenHelper
ScaleTo(Duration dur, float scale_x, float scale_y)
{
return TweenHelper(new kiwano::ActionScaleTo(dur, scale_x, scale_y));
}
/// \~chinese
/// @brief 构造相对缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放相对变化值
/// @param scale_y 纵向缩放相对变化值
static inline TweenHelper ScaleBy(Duration dur, float scale_x, float scale_y)
{
return TweenHelper(new kiwano::ActionScaleBy(dur, scale_x, scale_y));
}
/// \~chinese
/// @brief 构造透明度渐变动画
/// @param duration 动画时长
/// @param opacity 目标透明度
static inline TweenHelper
FadeTo(Duration dur, float opacity)
{
return TweenHelper(new kiwano::ActionFadeTo(dur, opacity));
}
/// \~chinese
/// @brief 构造缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放目标值
/// @param scale_y 纵向缩放目标值
static inline TweenHelper ScaleTo(Duration dur, float scale_x, float scale_y)
{
return TweenHelper(new kiwano::ActionScaleTo(dur, scale_x, scale_y));
}
/// \~chinese
/// @brief 构造淡入动画
/// @param duration 动画时长
static inline TweenHelper
FadeIn(Duration dur)
{
return TweenHelper(new kiwano::ActionFadeIn(dur));
}
/// \~chinese
/// @brief 构造透明度渐变动画
/// @param duration 动画时长
/// @param opacity 目标透明度
static inline TweenHelper FadeTo(Duration dur, float opacity)
{
return TweenHelper(new kiwano::ActionFadeTo(dur, opacity));
}
/// \~chinese
/// @brief 构造淡出动画
/// @param duration 动画时长
static inline TweenHelper
FadeOut(Duration dur)
{
return TweenHelper(new kiwano::ActionFadeOut(dur));
}
/// \~chinese
/// @brief 构造淡入动画
/// @param duration 动画时长
static inline TweenHelper FadeIn(Duration dur)
{
return TweenHelper(new kiwano::ActionFadeIn(dur));
}
/// \~chinese
/// @brief 构造相对旋转动画
/// @param duration 动画时长
/// @param rotation 角度相对变化值
static inline TweenHelper
RotateBy(Duration dur, float rotation)
{
return TweenHelper(new kiwano::ActionRotateBy(dur, rotation));
}
/// \~chinese
/// @brief 构造淡出动画
/// @param duration 动画时长
static inline TweenHelper FadeOut(Duration dur)
{
return TweenHelper(new kiwano::ActionFadeOut(dur));
}
/// \~chinese
/// @brief 构造旋转动画
/// @param duration 动画时长
/// @param rotation 目标角度
static inline TweenHelper
RotateTo(Duration dur, float rotation)
{
return TweenHelper(new kiwano::ActionRotateTo(dur, rotation));
}
/// \~chinese
/// @brief 构造相对旋转动画
/// @param duration 动画时长
/// @param rotation 角度相对变化值
static inline TweenHelper RotateBy(Duration dur, float rotation)
{
return TweenHelper(new kiwano::ActionRotateBy(dur, rotation));
}
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param path 路径几何形状
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
static inline TweenHelper
Walk(Duration duration, Geometry const& path, bool rotating = false, float start = 0.f, float end = 1.f)
{
return TweenHelper(new kiwano::ActionWalk(duration, path, rotating, start, end));
}
/// \~chinese
/// @brief 构造旋转动画
/// @param duration 动画时长
/// @param rotation 目标角度
static inline TweenHelper RotateTo(Duration dur, float rotation)
{
return TweenHelper(new kiwano::ActionRotateTo(dur, rotation));
}
/// \~chinese
/// @brief 构建帧动画
/// @param duration 动画时长
/// @param[in] frame_seq 序列帧
static inline TweenHelper
Animation(Duration dur, FrameSequencePtr frames)
{
return TweenHelper(new kiwano::Animation(dur, frames));
}
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param path 路径几何形状
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
static inline TweenHelper Walk(Duration duration, Geometry const& path, bool rotating = false, float start = 0.f,
float end = 1.f)
{
return TweenHelper(new kiwano::ActionWalk(duration, path, rotating, start, end));
}
/// \~chinese
/// @brief 构造自定义动画
/// @param duration 动画时长
/// @param tween_func 动画回调函数
static inline TweenHelper
Custom(Duration dur, ActionCustom::TweenFunc tween_func)
{
return TweenHelper(new kiwano::ActionCustom(dur, tween_func));
}
/// \~chinese
/// @brief 构建帧动画
/// @param duration 动画时长
/// @param[in] frame_seq 序列帧
static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames)
{
return TweenHelper(new kiwano::Animation(dur, frames));
}
/// \~chinese
/// @brief 构建延时动画
/// @param delay 延时时长
static inline ActionHelper
Delay(Duration delay)
{
return ActionHelper(new kiwano::ActionDelay(delay));
}
/// \~chinese
/// @brief 构造自定义动画
/// @param duration 动画时长
/// @param tween_func 动画回调函数
static inline TweenHelper Custom(Duration dur, ActionCustom::TweenFunc tween_func)
{
return TweenHelper(new kiwano::ActionCustom(dur, tween_func));
}
/// \~chinese
/// @brief 动画组合
/// @param actions 动画集合
/// @param sequence 动画按顺序依次执行或同时执行
static inline ActionHelper
Group(Vector<ActionPtr> const& actions, bool sequence = true)
{
return ActionHelper(new kiwano::ActionGroup(actions, sequence));
}
/// \~chinese
/// @brief 构建延时动画
/// @param delay 延时时长
static inline ActionHelper Delay(Duration delay)
{
return ActionHelper(new kiwano::ActionDelay(delay));
}
/// \~chinese
/// @brief 同步动画组合
/// @param actions 动画集合
static inline ActionHelper
Multiple(Vector<ActionPtr> const& actions)
{
return ActionHelper(new kiwano::ActionGroup(actions, false));
}
};
/// \~chinese
/// @brief 动画组合
/// @param actions 动画集合
/// @param sequence 动画按顺序依次执行或同时执行
static inline ActionHelper Group(Vector<ActionPtr> const& actions, bool sequence = true)
{
return ActionHelper(new kiwano::ActionGroup(actions, sequence));
}
/** @} */
}
/// \~chinese
/// @brief 同步动画组合
/// @param actions 动画集合
static inline ActionHelper Multiple(Vector<ActionPtr> const& actions)
{
return ActionHelper(new kiwano::ActionGroup(actions, false));
}
};
/** @} */
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,93 +18,93 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/2d/action/ActionManager.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/action/ActionManager.h>
#include <kiwano/core/Logger.h>
namespace kiwano
{
void ActionManager::UpdateActions(Actor* target, Duration dt)
{
if (actions_.empty() || !target)
return;
void ActionManager::UpdateActions(Actor* target, Duration dt)
{
if (actions_.empty() || !target)
return;
ActionPtr next;
for (auto action = actions_.first_item(); action; action = next)
{
next = action->next_item();
ActionPtr next;
for (auto action = actions_.first_item(); action; action = next)
{
next = action->next_item();
if (action->IsRunning())
action->UpdateStep(target, dt);
if (action->IsRunning())
action->UpdateStep(target, dt);
if (action->IsRemoveable())
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;
}
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_;
}
if (action->IsRemoveable())
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;
}
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

View File

@ -1,15 +1,15 @@
// 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
@ -23,59 +23,59 @@
namespace kiwano
{
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API ActionManager
{
public:
/// \~chinese
/// @brief 动画列表
using Actions = IntrusiveList<ActionPtr>;
/**
* \~chinese
* @brief
*/
class KGE_API ActionManager
{
public:
/// \~chinese
/// @brief 动画列表
using Actions = IntrusiveList<ActionPtr>;
/// \~chinese
/// @brief 添加动画
Action* AddAction(ActionPtr action);
/// \~chinese
/// @brief 添加动画
Action* AddAction(ActionPtr action);
/// \~chinese
/// @brief 添加动画
Action* AddAction(Action* action);
/// \~chinese
/// @brief 添加动画
Action* AddAction(Action* action);
/// \~chinese
/// @brief 继续所有暂停动画
void ResumeAllActions();
/// \~chinese
/// @brief 继续所有暂停动画
void ResumeAllActions();
/// \~chinese
/// @brief 暂停所有动画
void PauseAllActions();
/// \~chinese
/// @brief 暂停所有动画
void PauseAllActions();
/// \~chinese
/// @brief 停止所有动画
void StopAllActions();
/// \~chinese
/// @brief 停止所有动画
void StopAllActions();
/// \~chinese
/// @brief 获取指定名称的动画
/// @param name 动画名称
ActionPtr GetAction(String const& name);
/// \~chinese
/// @brief 获取指定名称的动画
/// @param name 动画名称
ActionPtr GetAction(String const& name);
/// \~chinese
/// @brief 获取所有动画
Actions const& GetAllActions() const;
/// \~chinese
/// @brief 获取所有动画
Actions const& GetAllActions() const;
protected:
/// \~chinese
/// @brief 更新动画
void UpdateActions(Actor* target, Duration dt);
protected:
/// \~chinese
/// @brief 更新动画
void UpdateActions(Actor* target, Duration dt);
private:
Actions actions_;
};
private:
Actions actions_;
};
/** @} */
}
/** @} */
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,420 +19,432 @@
// THE SOFTWARE.
#include <functional>
#include <kiwano/2d/action/ActionTween.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/action/ActionTween.h>
namespace kiwano
{
//-------------------------------------------------------
// Ease Functions
//-------------------------------------------------------
inline EaseFunc MakeEaseIn(float rate) { return std::bind(math::EaseIn, std::placeholders::_1, rate); }
inline EaseFunc MakeEaseOut(float rate) { return std::bind(math::EaseOut, std::placeholders::_1, rate); }
inline EaseFunc MakeEaseInOut(float rate) { return std::bind(math::EaseInOut, std::placeholders::_1, rate); }
inline EaseFunc MakeEaseElasticIn(float period) { return std::bind(math::EaseElasticIn, std::placeholders::_1, period); }
inline EaseFunc MakeEaseElasticOut(float period) { return std::bind(math::EaseElasticOut, std::placeholders::_1, period); }
inline EaseFunc MakeEaseElasticInOut(float period) { return std::bind(math::EaseElasticInOut, std::placeholders::_1, period); }
KGE_API EaseFunc Ease::Linear = math::Linear;
KGE_API EaseFunc Ease::EaseIn = MakeEaseIn(2.f);
KGE_API EaseFunc Ease::EaseOut = MakeEaseOut(2.f);
KGE_API EaseFunc Ease::EaseInOut = MakeEaseInOut(2.f);
KGE_API EaseFunc Ease::ExpoIn = math::EaseExponentialIn;
KGE_API EaseFunc Ease::ExpoOut = math::EaseExponentialOut;
KGE_API EaseFunc Ease::ExpoInOut = math::EaseExponentialInOut;
KGE_API EaseFunc Ease::BounceIn = math::EaseBounceIn;
KGE_API EaseFunc Ease::BounceOut = math::EaseBounceOut;
KGE_API EaseFunc Ease::BounceInOut = math::EaseBounceInOut;
KGE_API EaseFunc Ease::ElasticIn = MakeEaseElasticIn(0.3f);
KGE_API EaseFunc Ease::ElasticOut = MakeEaseElasticOut(0.3f);
KGE_API EaseFunc Ease::ElasticInOut = MakeEaseElasticInOut(0.3f);
KGE_API EaseFunc Ease::SineIn = math::EaseSineIn;
KGE_API EaseFunc Ease::SineOut = math::EaseSineOut;
KGE_API EaseFunc Ease::SineInOut = math::EaseSineInOut;
KGE_API EaseFunc Ease::BackIn = math::EaseBackIn;
KGE_API EaseFunc Ease::BackOut = math::EaseBackOut;
KGE_API EaseFunc Ease::BackInOut = math::EaseBackInOut;
KGE_API EaseFunc Ease::QuadIn = math::EaseQuadIn;
KGE_API EaseFunc Ease::QuadOut = math::EaseQuadOut;
KGE_API EaseFunc Ease::QuadInOut = math::EaseQuadInOut;
KGE_API EaseFunc Ease::CubicIn = math::EaseCubicIn;
KGE_API EaseFunc Ease::CubicOut = math::EaseCubicOut;
KGE_API EaseFunc Ease::CubicInOut = math::EaseCubicInOut;
KGE_API EaseFunc Ease::QuartIn = math::EaseQuartIn;
KGE_API EaseFunc Ease::QuartOut = math::EaseQuartOut;
KGE_API EaseFunc Ease::QuartInOut = math::EaseQuartInOut;
KGE_API EaseFunc Ease::QuintIn = math::EaseQuintIn;
KGE_API EaseFunc Ease::QuintOut = math::EaseQuintOut;
KGE_API EaseFunc Ease::QuintInOut = math::EaseQuintInOut;
//-------------------------------------------------------
// ActionTween
//-------------------------------------------------------
ActionTween::ActionTween()
: dur_()
, ease_func_(nullptr)
{
}
ActionTween::ActionTween(Duration duration, EaseFunc func)
{
SetDuration(duration);
SetEaseFunc(func);
}
void ActionTween::SetEaseFunc(EaseFunc const& func)
{
ease_func_ = func;
}
EaseFunc const & ActionTween::GetEaseFunc() const
{
return ease_func_;
}
Duration ActionTween::GetDuration() const
{
return dur_;
}
void ActionTween::Update(Actor* target, Duration dt)
{
float percent;
if (dur_.IsZero())
{
percent = 1.f;
Complete(target);
}
else
{
Duration elapsed = GetElapsed() - GetDelay();
float loops_done = elapsed / dur_;
while (GetLoopsDone() < static_cast<int>(loops_done))
{
Complete(target); // loops_done_++
}
percent = (GetStatus() == Status::Done) ? 1.f : (loops_done - static_cast<float>(GetLoopsDone()));
}
if (ease_func_)
percent = ease_func_(percent);
UpdateTween(target, percent);
}
void ActionTween::SetDuration(Duration duration)
{
dur_ = duration;
}
//-------------------------------------------------------
// Move Action
//-------------------------------------------------------
ActionMoveBy::ActionMoveBy(Duration duration, Vec2 const& vector, EaseFunc func)
: ActionTween(duration, func)
{
delta_pos_ = vector;
}
void ActionMoveBy::Init(Actor* target)
{
if (target)
{
prev_pos_ = start_pos_ = target->GetPosition();
}
}
void ActionMoveBy::UpdateTween(Actor* target, float percent)
{
Point diff = target->GetPosition() - prev_pos_;
start_pos_ = start_pos_ + diff;
Point new_pos = start_pos_ + (delta_pos_ * percent);
target->SetPosition(new_pos);
prev_pos_ = new_pos;
}
ActionPtr ActionMoveBy::Clone() const
{
return new (std::nothrow) ActionMoveBy(GetDuration(), delta_pos_, GetEaseFunc());
}
ActionPtr ActionMoveBy::Reverse() const
{
return new (std::nothrow) ActionMoveBy(GetDuration(), -delta_pos_, GetEaseFunc());
}
ActionMoveTo::ActionMoveTo(Duration duration, Point const& pos, EaseFunc func)
: ActionMoveBy(duration, Point(), func)
{
end_pos_ = pos;
}
ActionPtr ActionMoveTo::Clone() const
{
return new (std::nothrow) ActionMoveTo(GetDuration(), end_pos_, GetEaseFunc());
}
void ActionMoveTo::Init(Actor* target)
{
ActionMoveBy::Init(target);
delta_pos_ = end_pos_ - start_pos_;
}
//-------------------------------------------------------
// Jump Action
//-------------------------------------------------------
ActionJumpBy::ActionJumpBy(Duration duration, Vec2 const& vec, float height, int jumps, EaseFunc func)
: ActionTween(duration, func)
, delta_pos_(vec)
, height_(height)
, jumps_(jumps)
{
}
ActionPtr ActionJumpBy::Clone() const
{
return new (std::nothrow) ActionJumpBy(GetDuration(), delta_pos_, height_, jumps_, GetEaseFunc());
}
ActionPtr ActionJumpBy::Reverse() const
{
return new (std::nothrow) ActionJumpBy(GetDuration(), -delta_pos_, height_, jumps_, GetEaseFunc());
}
void ActionJumpBy::Init(Actor* target)
{
if (target)
{
prev_pos_ = start_pos_ = target->GetPosition();
}
}
void ActionJumpBy::UpdateTween(Actor* target, float percent)
{
float frac = fmod(percent * jumps_, 1.f);
float x = delta_pos_.x * percent;
float y = height_ * 4 * frac * (1 - frac);
y += delta_pos_.y * percent;
Point diff = target->GetPosition() - prev_pos_;
start_pos_ = diff + start_pos_;
Point new_pos = start_pos_ + Point(x, y);
target->SetPosition(new_pos);
prev_pos_ = new_pos;
}
ActionJumpTo::ActionJumpTo(Duration duration, Point const& pos, float height, int jumps, EaseFunc func)
: ActionJumpBy(duration, Point(), height, jumps, func)
, end_pos_(pos)
{
}
ActionPtr ActionJumpTo::Clone() const
{
return new (std::nothrow) ActionJumpTo(GetDuration(), end_pos_, height_, jumps_, GetEaseFunc());
}
void ActionJumpTo::Init(Actor* target)
{
ActionJumpBy::Init(target);
delta_pos_ = end_pos_ - start_pos_;
}
//-------------------------------------------------------
// Scale Action
//-------------------------------------------------------
ActionScaleBy::ActionScaleBy(Duration duration, float scale_x, float scale_y, EaseFunc func)
: ActionTween(duration, func)
, delta_x_(scale_x)
, delta_y_(scale_y)
, start_scale_x_(0.f)
, start_scale_y_(0.f)
{
}
void ActionScaleBy::Init(Actor* target)
{
if (target)
{
start_scale_x_ = target->GetScaleX();
start_scale_y_ = target->GetScaleY();
}
}
void ActionScaleBy::UpdateTween(Actor* target, float percent)
{
target->SetScale(Vec2{ start_scale_x_ + delta_x_ * percent, start_scale_y_ + delta_y_ * percent });
}
ActionPtr ActionScaleBy::Clone() const
{
return new (std::nothrow) ActionScaleBy(GetDuration(), delta_x_, delta_y_, GetEaseFunc());
}
ActionPtr ActionScaleBy::Reverse() const
{
return new (std::nothrow) ActionScaleBy(GetDuration(), -delta_x_, -delta_y_, GetEaseFunc());
}
ActionScaleTo::ActionScaleTo(Duration duration, float scale_x, float scale_y, EaseFunc func)
: ActionScaleBy(duration, 0, 0, func)
{
end_scale_x_ = scale_x;
end_scale_y_ = scale_y;
}
ActionPtr ActionScaleTo::Clone() const
{
return new (std::nothrow) ActionScaleTo(GetDuration(), end_scale_x_, end_scale_y_, GetEaseFunc());
}
void ActionScaleTo::Init(Actor* target)
{
ActionScaleBy::Init(target);
delta_x_ = end_scale_x_ - start_scale_x_;
delta_y_ = end_scale_y_ - start_scale_y_;
}
//-------------------------------------------------------
// Opacity Action
//-------------------------------------------------------
ActionFadeTo::ActionFadeTo(Duration duration, float opacity, EaseFunc func)
: ActionTween(duration, func)
, delta_val_(0.f)
, start_val_(0.f)
, end_val_(opacity)
{
}
void ActionFadeTo::Init(Actor* target)
{
if (target)
{
start_val_ = target->GetOpacity();
delta_val_ = end_val_ - start_val_;
}
}
void ActionFadeTo::UpdateTween(Actor* target, float percent)
{
target->SetOpacity(start_val_ + delta_val_ * percent);
}
ActionPtr ActionFadeTo::Clone() const
{
return new (std::nothrow) ActionFadeTo(GetDuration(), end_val_, GetEaseFunc());
}
ActionFadeIn::ActionFadeIn(Duration duration, EaseFunc func)
: ActionFadeTo(duration, 1, func)
{
}
ActionFadeOut::ActionFadeOut(Duration duration, EaseFunc func)
: ActionFadeTo(duration, 0, func)
{
}
//-------------------------------------------------------
// Rotate Action
//-------------------------------------------------------
ActionRotateBy::ActionRotateBy(Duration duration, float rotation, EaseFunc func)
: ActionTween(duration, func)
, start_val_()
, delta_val_(rotation)
{
}
void ActionRotateBy::Init(Actor* target)
{
if (target)
{
start_val_ = target->GetRotation();
}
}
void ActionRotateBy::UpdateTween(Actor* target, float percent)
{
float rotation = start_val_ + delta_val_ * percent;
if (rotation > 360.f)
rotation -= 360.f;
target->SetRotation(rotation);
}
ActionPtr ActionRotateBy::Clone() const
{
return new (std::nothrow) ActionRotateBy(GetDuration(), delta_val_, GetEaseFunc());
}
ActionPtr ActionRotateBy::Reverse() const
{
return new (std::nothrow) ActionRotateBy(GetDuration(), -delta_val_, GetEaseFunc());
}
ActionRotateTo::ActionRotateTo(Duration duration, float rotation, EaseFunc func)
: ActionRotateBy(duration, 0, func)
{
end_val_ = rotation;
}
ActionPtr ActionRotateTo::Clone() const
{
return new (std::nothrow) ActionRotateTo(GetDuration(), end_val_, GetEaseFunc());
}
void ActionRotateTo::Init(Actor* target)
{
ActionRotateBy::Init(target);
delta_val_ = end_val_ - start_val_;
}
//-------------------------------------------------------
// ActionCustom
//-------------------------------------------------------
ActionCustom::ActionCustom(Duration duration, TweenFunc tween_func, EaseFunc func)
: ActionTween(duration, func)
, tween_func_(tween_func)
{
}
ActionPtr ActionCustom::Clone() const
{
return new ActionCustom(GetDuration(), tween_func_);
}
void ActionCustom::Init(Actor* target)
{
if (!tween_func_)
this->Done();
}
void ActionCustom::UpdateTween(Actor* target, float percent)
{
if (tween_func_)
tween_func_(target, percent);
}
//-------------------------------------------------------
// Ease Functions
//-------------------------------------------------------
inline EaseFunc MakeEaseIn(float rate)
{
return std::bind(math::EaseIn, std::placeholders::_1, rate);
}
inline EaseFunc MakeEaseOut(float rate)
{
return std::bind(math::EaseOut, std::placeholders::_1, rate);
}
inline EaseFunc MakeEaseInOut(float rate)
{
return std::bind(math::EaseInOut, std::placeholders::_1, rate);
}
inline EaseFunc MakeEaseElasticIn(float period)
{
return std::bind(math::EaseElasticIn, std::placeholders::_1, period);
}
inline EaseFunc MakeEaseElasticOut(float period)
{
return std::bind(math::EaseElasticOut, std::placeholders::_1, period);
}
inline EaseFunc MakeEaseElasticInOut(float period)
{
return std::bind(math::EaseElasticInOut, std::placeholders::_1, period);
}
KGE_API EaseFunc Ease::Linear = math::Linear;
KGE_API EaseFunc Ease::EaseIn = MakeEaseIn(2.f);
KGE_API EaseFunc Ease::EaseOut = MakeEaseOut(2.f);
KGE_API EaseFunc Ease::EaseInOut = MakeEaseInOut(2.f);
KGE_API EaseFunc Ease::ExpoIn = math::EaseExponentialIn;
KGE_API EaseFunc Ease::ExpoOut = math::EaseExponentialOut;
KGE_API EaseFunc Ease::ExpoInOut = math::EaseExponentialInOut;
KGE_API EaseFunc Ease::BounceIn = math::EaseBounceIn;
KGE_API EaseFunc Ease::BounceOut = math::EaseBounceOut;
KGE_API EaseFunc Ease::BounceInOut = math::EaseBounceInOut;
KGE_API EaseFunc Ease::ElasticIn = MakeEaseElasticIn(0.3f);
KGE_API EaseFunc Ease::ElasticOut = MakeEaseElasticOut(0.3f);
KGE_API EaseFunc Ease::ElasticInOut = MakeEaseElasticInOut(0.3f);
KGE_API EaseFunc Ease::SineIn = math::EaseSineIn;
KGE_API EaseFunc Ease::SineOut = math::EaseSineOut;
KGE_API EaseFunc Ease::SineInOut = math::EaseSineInOut;
KGE_API EaseFunc Ease::BackIn = math::EaseBackIn;
KGE_API EaseFunc Ease::BackOut = math::EaseBackOut;
KGE_API EaseFunc Ease::BackInOut = math::EaseBackInOut;
KGE_API EaseFunc Ease::QuadIn = math::EaseQuadIn;
KGE_API EaseFunc Ease::QuadOut = math::EaseQuadOut;
KGE_API EaseFunc Ease::QuadInOut = math::EaseQuadInOut;
KGE_API EaseFunc Ease::CubicIn = math::EaseCubicIn;
KGE_API EaseFunc Ease::CubicOut = math::EaseCubicOut;
KGE_API EaseFunc Ease::CubicInOut = math::EaseCubicInOut;
KGE_API EaseFunc Ease::QuartIn = math::EaseQuartIn;
KGE_API EaseFunc Ease::QuartOut = math::EaseQuartOut;
KGE_API EaseFunc Ease::QuartInOut = math::EaseQuartInOut;
KGE_API EaseFunc Ease::QuintIn = math::EaseQuintIn;
KGE_API EaseFunc Ease::QuintOut = math::EaseQuintOut;
KGE_API EaseFunc Ease::QuintInOut = math::EaseQuintInOut;
//-------------------------------------------------------
// ActionTween
//-------------------------------------------------------
ActionTween::ActionTween()
: dur_()
, ease_func_(nullptr)
{
}
ActionTween::ActionTween(Duration duration, EaseFunc func)
{
SetDuration(duration);
SetEaseFunc(func);
}
void ActionTween::SetEaseFunc(EaseFunc const& func)
{
ease_func_ = func;
}
EaseFunc const& ActionTween::GetEaseFunc() const
{
return ease_func_;
}
Duration ActionTween::GetDuration() const
{
return dur_;
}
void ActionTween::Update(Actor* target, Duration dt)
{
float percent;
if (dur_.IsZero())
{
percent = 1.f;
Complete(target);
}
else
{
Duration elapsed = GetElapsed() - GetDelay();
float loops_done = elapsed / dur_;
while (GetLoopsDone() < static_cast<int>(loops_done))
{
Complete(target); // loops_done_++
}
percent = (GetStatus() == Status::Done) ? 1.f : (loops_done - static_cast<float>(GetLoopsDone()));
}
if (ease_func_)
percent = ease_func_(percent);
UpdateTween(target, percent);
}
void ActionTween::SetDuration(Duration duration)
{
dur_ = duration;
}
//-------------------------------------------------------
// Move Action
//-------------------------------------------------------
ActionMoveBy::ActionMoveBy(Duration duration, Vec2 const& vector, EaseFunc func)
: ActionTween(duration, func)
{
delta_pos_ = vector;
}
void ActionMoveBy::Init(Actor* target)
{
if (target)
{
prev_pos_ = start_pos_ = target->GetPosition();
}
}
void ActionMoveBy::UpdateTween(Actor* target, float percent)
{
Point diff = target->GetPosition() - prev_pos_;
start_pos_ = start_pos_ + diff;
Point new_pos = start_pos_ + (delta_pos_ * percent);
target->SetPosition(new_pos);
prev_pos_ = new_pos;
}
ActionPtr ActionMoveBy::Clone() const
{
return new (std::nothrow) ActionMoveBy(GetDuration(), delta_pos_, GetEaseFunc());
}
ActionPtr ActionMoveBy::Reverse() const
{
return new (std::nothrow) ActionMoveBy(GetDuration(), -delta_pos_, GetEaseFunc());
}
ActionMoveTo::ActionMoveTo(Duration duration, Point const& pos, EaseFunc func)
: ActionMoveBy(duration, Point(), func)
{
end_pos_ = pos;
}
ActionPtr ActionMoveTo::Clone() const
{
return new (std::nothrow) ActionMoveTo(GetDuration(), end_pos_, GetEaseFunc());
}
void ActionMoveTo::Init(Actor* target)
{
ActionMoveBy::Init(target);
delta_pos_ = end_pos_ - start_pos_;
}
//-------------------------------------------------------
// Jump Action
//-------------------------------------------------------
ActionJumpBy::ActionJumpBy(Duration duration, Vec2 const& vec, float height, int jumps, EaseFunc func)
: ActionTween(duration, func)
, delta_pos_(vec)
, height_(height)
, jumps_(jumps)
{
}
ActionPtr ActionJumpBy::Clone() const
{
return new (std::nothrow) ActionJumpBy(GetDuration(), delta_pos_, height_, jumps_, GetEaseFunc());
}
ActionPtr ActionJumpBy::Reverse() const
{
return new (std::nothrow) ActionJumpBy(GetDuration(), -delta_pos_, height_, jumps_, GetEaseFunc());
}
void ActionJumpBy::Init(Actor* target)
{
if (target)
{
prev_pos_ = start_pos_ = target->GetPosition();
}
}
void ActionJumpBy::UpdateTween(Actor* target, float percent)
{
float frac = fmod(percent * jumps_, 1.f);
float x = delta_pos_.x * percent;
float y = height_ * 4 * frac * (1 - frac);
y += delta_pos_.y * percent;
Point diff = target->GetPosition() - prev_pos_;
start_pos_ = diff + start_pos_;
Point new_pos = start_pos_ + Point(x, y);
target->SetPosition(new_pos);
prev_pos_ = new_pos;
}
ActionJumpTo::ActionJumpTo(Duration duration, Point const& pos, float height, int jumps, EaseFunc func)
: ActionJumpBy(duration, Point(), height, jumps, func)
, end_pos_(pos)
{
}
ActionPtr ActionJumpTo::Clone() const
{
return new (std::nothrow) ActionJumpTo(GetDuration(), end_pos_, height_, jumps_, GetEaseFunc());
}
void ActionJumpTo::Init(Actor* target)
{
ActionJumpBy::Init(target);
delta_pos_ = end_pos_ - start_pos_;
}
//-------------------------------------------------------
// Scale Action
//-------------------------------------------------------
ActionScaleBy::ActionScaleBy(Duration duration, float scale_x, float scale_y, EaseFunc func)
: ActionTween(duration, func)
, delta_x_(scale_x)
, delta_y_(scale_y)
, start_scale_x_(0.f)
, start_scale_y_(0.f)
{
}
void ActionScaleBy::Init(Actor* target)
{
if (target)
{
start_scale_x_ = target->GetScaleX();
start_scale_y_ = target->GetScaleY();
}
}
void ActionScaleBy::UpdateTween(Actor* target, float percent)
{
target->SetScale(Vec2{ start_scale_x_ + delta_x_ * percent, start_scale_y_ + delta_y_ * percent });
}
ActionPtr ActionScaleBy::Clone() const
{
return new (std::nothrow) ActionScaleBy(GetDuration(), delta_x_, delta_y_, GetEaseFunc());
}
ActionPtr ActionScaleBy::Reverse() const
{
return new (std::nothrow) ActionScaleBy(GetDuration(), -delta_x_, -delta_y_, GetEaseFunc());
}
ActionScaleTo::ActionScaleTo(Duration duration, float scale_x, float scale_y, EaseFunc func)
: ActionScaleBy(duration, 0, 0, func)
{
end_scale_x_ = scale_x;
end_scale_y_ = scale_y;
}
ActionPtr ActionScaleTo::Clone() const
{
return new (std::nothrow) ActionScaleTo(GetDuration(), end_scale_x_, end_scale_y_, GetEaseFunc());
}
void ActionScaleTo::Init(Actor* target)
{
ActionScaleBy::Init(target);
delta_x_ = end_scale_x_ - start_scale_x_;
delta_y_ = end_scale_y_ - start_scale_y_;
}
//-------------------------------------------------------
// Opacity Action
//-------------------------------------------------------
ActionFadeTo::ActionFadeTo(Duration duration, float opacity, EaseFunc func)
: ActionTween(duration, func)
, delta_val_(0.f)
, start_val_(0.f)
, end_val_(opacity)
{
}
void ActionFadeTo::Init(Actor* target)
{
if (target)
{
start_val_ = target->GetOpacity();
delta_val_ = end_val_ - start_val_;
}
}
void ActionFadeTo::UpdateTween(Actor* target, float percent)
{
target->SetOpacity(start_val_ + delta_val_ * percent);
}
ActionPtr ActionFadeTo::Clone() const
{
return new (std::nothrow) ActionFadeTo(GetDuration(), end_val_, GetEaseFunc());
}
ActionFadeIn::ActionFadeIn(Duration duration, EaseFunc func)
: ActionFadeTo(duration, 1, func)
{
}
ActionFadeOut::ActionFadeOut(Duration duration, EaseFunc func)
: ActionFadeTo(duration, 0, func)
{
}
//-------------------------------------------------------
// Rotate Action
//-------------------------------------------------------
ActionRotateBy::ActionRotateBy(Duration duration, float rotation, EaseFunc func)
: ActionTween(duration, func)
, start_val_()
, delta_val_(rotation)
{
}
void ActionRotateBy::Init(Actor* target)
{
if (target)
{
start_val_ = target->GetRotation();
}
}
void ActionRotateBy::UpdateTween(Actor* target, float percent)
{
float rotation = start_val_ + delta_val_ * percent;
if (rotation > 360.f)
rotation -= 360.f;
target->SetRotation(rotation);
}
ActionPtr ActionRotateBy::Clone() const
{
return new (std::nothrow) ActionRotateBy(GetDuration(), delta_val_, GetEaseFunc());
}
ActionPtr ActionRotateBy::Reverse() const
{
return new (std::nothrow) ActionRotateBy(GetDuration(), -delta_val_, GetEaseFunc());
}
ActionRotateTo::ActionRotateTo(Duration duration, float rotation, EaseFunc func)
: ActionRotateBy(duration, 0, func)
{
end_val_ = rotation;
}
ActionPtr ActionRotateTo::Clone() const
{
return new (std::nothrow) ActionRotateTo(GetDuration(), end_val_, GetEaseFunc());
}
void ActionRotateTo::Init(Actor* target)
{
ActionRotateBy::Init(target);
delta_val_ = end_val_ - start_val_;
}
//-------------------------------------------------------
// ActionCustom
//-------------------------------------------------------
ActionCustom::ActionCustom(Duration duration, TweenFunc tween_func, EaseFunc func)
: ActionTween(duration, func)
, tween_func_(tween_func)
{
}
ActionPtr ActionCustom::Clone() const
{
return new ActionCustom(GetDuration(), tween_func_);
}
void ActionCustom::Init(Actor* target)
{
if (!tween_func_)
this->Done();
}
void ActionCustom::UpdateTween(Actor* target, float percent)
{
if (tween_func_)
tween_func_(target, percent);
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -24,487 +24,460 @@
namespace kiwano
{
/// \~chinese
/// @brief 缓动函数
using EaseFunc = Function<float(float)>;
/// \~chinese
/// @brief 缓动函数枚举
/// @details 查看 https://easings.net 获取更多信息
struct Ease
{
static KGE_API EaseFunc Linear; ///< 线性
static KGE_API EaseFunc EaseIn; ///< 由慢变快
static KGE_API EaseFunc EaseOut; ///< 由快变慢
static KGE_API EaseFunc EaseInOut; ///< 由慢变快, 再由快变慢
static KGE_API EaseFunc ExpoIn; ///< 由慢变极快
static KGE_API EaseFunc ExpoOut; ///< 由极快变慢
static KGE_API EaseFunc ExpoInOut; ///< 由慢至极快, 再由极快边慢
static KGE_API EaseFunc ElasticIn; ///< 自起点赋予弹性
static KGE_API EaseFunc ElasticOut; ///< 自终点赋予弹性
static KGE_API EaseFunc ElasticInOut; ///< 再起点和终点赋予弹性
static KGE_API EaseFunc BounceIn; ///< 自起点赋予反弹力
static KGE_API EaseFunc BounceOut; ///< 自终点赋予反弹力
static KGE_API EaseFunc BounceInOut; ///< 在起点和终点赋予反弹力
static KGE_API EaseFunc BackIn;
static KGE_API EaseFunc BackOut;
static KGE_API EaseFunc BackInOut;
static KGE_API EaseFunc QuadIn;
static KGE_API EaseFunc QuadOut;
static KGE_API EaseFunc QuadInOut;
static KGE_API EaseFunc CubicIn;
static KGE_API EaseFunc CubicOut;
static KGE_API EaseFunc CubicInOut;
static KGE_API EaseFunc QuartIn;
static KGE_API EaseFunc QuartOut;
static KGE_API EaseFunc QuartInOut;
static KGE_API EaseFunc QuintIn;
static KGE_API EaseFunc QuintOut;
static KGE_API EaseFunc QuintInOut;
static KGE_API EaseFunc SineIn;
static KGE_API EaseFunc SineOut;
static KGE_API EaseFunc SineInOut;
};
KGE_DECLARE_SMART_PTR(ActionTween);
KGE_DECLARE_SMART_PTR(ActionMoveBy);
KGE_DECLARE_SMART_PTR(ActionMoveTo);
KGE_DECLARE_SMART_PTR(ActionJumpBy);
KGE_DECLARE_SMART_PTR(ActionJumpTo);
KGE_DECLARE_SMART_PTR(ActionScaleBy);
KGE_DECLARE_SMART_PTR(ActionScaleTo);
KGE_DECLARE_SMART_PTR(ActionFadeTo);
KGE_DECLARE_SMART_PTR(ActionFadeIn);
KGE_DECLARE_SMART_PTR(ActionFadeOut);
KGE_DECLARE_SMART_PTR(ActionRotateBy);
KGE_DECLARE_SMART_PTR(ActionRotateTo);
KGE_DECLARE_SMART_PTR(ActionCustom);
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 补间动画
class KGE_API ActionTween
: public Action
{
public:
ActionTween();
/// \~chinese
/// @brief 补间动画
/// @param duration 动画时长
/// @param func 动画速度缓动函数
ActionTween(Duration duration, EaseFunc func);
/// \~chinese
/// @brief 获取动画时长
Duration GetDuration() const;
/// \~chinese
/// @brief 设置动画时长
void SetDuration(Duration duration);
/// \~chinese
/// @brief 获取动画速度缓动函数
EaseFunc const& GetEaseFunc() const;
/// \~chinese
/// @brief 设置动画速度缓动函数
void SetEaseFunc(EaseFunc const& func);
protected:
void Update(Actor* target, Duration dt) override;
virtual void UpdateTween(Actor* target, float percent) = 0;
private:
Duration dur_;
EaseFunc ease_func_;
};
/// \~chinese
/// @brief 相对位移动画
class KGE_API ActionMoveBy
: public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对位移动画
/// @param duration 动画时长
/// @param vector 移动向量
/// @param func 动画速度缓动函数
ActionMoveBy(Duration duration, Vec2 const& vector, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
Point start_pos_;
Point prev_pos_;
Vec2 delta_pos_;
};
/// \~chinese
/// @brief 位移动画
class KGE_API ActionMoveTo
: public ActionMoveBy
{
public:
/// \~chinese
/// @brief 构造位移动画
/// @param duration 动画时长
/// @param pos 目的坐标
/// @param func 动画速度缓动函数
ActionMoveTo(Duration duration, Point const& pos, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionMoveTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
Point end_pos_;
};
/// \~chinese
/// @brief 相对跳跃动画
class KGE_API ActionJumpBy
: public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对跳跃动画
/// @param duration 动画时长
/// @param vec 跳跃位移向量
/// @param height 跳跃高度
/// @param jumps 跳跃次数
/// @param func 动画速度缓动函数
ActionJumpBy(Duration duration, Vec2 const& vec, float height, int jumps = 1, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
Point start_pos_;
Point delta_pos_;
float height_;
int jumps_;
Point prev_pos_;
};
/// \~chinese
/// @brief 跳跃动画
class KGE_API ActionJumpTo
: public ActionJumpBy
{
public:
/// \~chinese
/// @brief 构造跳跃动画
/// @param duration 动画时长
/// @param pos 目的坐标
/// @param height 跳跃高度
/// @param jumps 跳跃次数
/// @param func 动画速度缓动函数
ActionJumpTo(Duration duration, Point const& pos, float height, int jumps = 1, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionJumpTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
Point end_pos_;
};
/// \~chinese
/// @brief 相对缩放动画
class KGE_API ActionScaleBy
: public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放相对变化值
/// @param scale_y 纵向缩放相对变化值
/// @param func 动画速度缓动函数
ActionScaleBy(Duration duration, float scale_x, float scale_y, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
float start_scale_x_;
float start_scale_y_;
float delta_x_;
float delta_y_;
};
/// \~chinese
/// @brief 缩放动画
class KGE_API ActionScaleTo
: public ActionScaleBy
{
public:
/// \~chinese
/// @brief 构造缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放目标值
/// @param scale_y 纵向缩放目标值
/// @param func 动画速度缓动函数
ActionScaleTo(Duration duration, float scale_x, float scale_y, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionScaleTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
float end_scale_x_;
float end_scale_y_;
};
/// \~chinese
/// @brief 透明度渐变动画
class KGE_API ActionFadeTo
: public ActionTween
{
public:
/// \~chinese
/// @brief 构造透明度渐变动画
/// @param duration 动画时长
/// @param opacity 目标透明度
/// @param func 动画速度缓动函数
ActionFadeTo(Duration duration, float opacity, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionFadeTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
private:
float start_val_;
float delta_val_;
float end_val_;
};
/// \~chinese
/// @brief 淡入动画
class KGE_API ActionFadeIn
: public ActionFadeTo
{
public:
/// \~chinese
/// @brief 构造淡入动画
/// @param duration 动画时长
/// @param func 动画速度缓动函数
explicit ActionFadeIn(Duration duration, EaseFunc func = nullptr);
};
/// \~chinese
/// @brief 淡出动画
class KGE_API ActionFadeOut
: public ActionFadeTo
{
public:
/// \~chinese
/// @brief 构造淡出动画
/// @param duration 动画时长
/// @param func 动画速度缓动函数
explicit ActionFadeOut(Duration duration, EaseFunc func = nullptr);
};
/// \~chinese
/// @brief 相对旋转动画
class KGE_API ActionRotateBy
: public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对旋转动画
/// @param duration 动画时长
/// @param rotation 角度相对变化值
/// @param func 动画速度缓动函数
ActionRotateBy(Duration duration, float rotation, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
float start_val_;
float delta_val_;
};
/// \~chinese
/// @brief 旋转动画
class KGE_API ActionRotateTo
: public ActionRotateBy
{
public:
/// \~chinese
/// @brief 构造旋转动画
/// @param duration 动画时长
/// @param rotation 目标角度
/// @param func 动画速度缓动函数
ActionRotateTo(Duration duration, float rotation, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionRotateTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
float end_val_;
};
/// \~chinese
/// @brief 自定义动画
class KGE_API ActionCustom
: public ActionTween
{
public:
/// \~chinese
/// @brief 动画回调函数
/// @details 在动画更新时回调该函数第一个参数是执行动画的目标第二个参数是动画进度0.0 - 1.0
using TweenFunc = Function<void(Actor* /* target */, float /* percent */)>;
/// \~chinese
/// @brief 构造自定义动画
/// @param duration 动画时长
/// @param tween_func 动画回调函数
/// @param func 动画速度缓动函数
ActionCustom(Duration duration, TweenFunc tween_func, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionCustom");
return nullptr;
}
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
private:
TweenFunc tween_func_;
};
/** @} */
}
/// \~chinese
/// @brief 缓动函数
using EaseFunc = Function<float(float)>;
/// \~chinese
/// @brief 缓动函数枚举
/// @details 查看 https://easings.net 获取更多信息
struct Ease
{
static KGE_API EaseFunc Linear; ///< 线性
static KGE_API EaseFunc EaseIn; ///< 由慢变快
static KGE_API EaseFunc EaseOut; ///< 由快变慢
static KGE_API EaseFunc EaseInOut; ///< 由慢变快, 再由快变慢
static KGE_API EaseFunc ExpoIn; ///< 由慢变极快
static KGE_API EaseFunc ExpoOut; ///< 由极快变慢
static KGE_API EaseFunc ExpoInOut; ///< 由慢至极快, 再由极快边慢
static KGE_API EaseFunc ElasticIn; ///< 自起点赋予弹性
static KGE_API EaseFunc ElasticOut; ///< 自终点赋予弹性
static KGE_API EaseFunc ElasticInOut; ///< 再起点和终点赋予弹性
static KGE_API EaseFunc BounceIn; ///< 自起点赋予反弹力
static KGE_API EaseFunc BounceOut; ///< 自终点赋予反弹力
static KGE_API EaseFunc BounceInOut; ///< 在起点和终点赋予反弹力
static KGE_API EaseFunc BackIn;
static KGE_API EaseFunc BackOut;
static KGE_API EaseFunc BackInOut;
static KGE_API EaseFunc QuadIn;
static KGE_API EaseFunc QuadOut;
static KGE_API EaseFunc QuadInOut;
static KGE_API EaseFunc CubicIn;
static KGE_API EaseFunc CubicOut;
static KGE_API EaseFunc CubicInOut;
static KGE_API EaseFunc QuartIn;
static KGE_API EaseFunc QuartOut;
static KGE_API EaseFunc QuartInOut;
static KGE_API EaseFunc QuintIn;
static KGE_API EaseFunc QuintOut;
static KGE_API EaseFunc QuintInOut;
static KGE_API EaseFunc SineIn;
static KGE_API EaseFunc SineOut;
static KGE_API EaseFunc SineInOut;
};
KGE_DECLARE_SMART_PTR(ActionTween);
KGE_DECLARE_SMART_PTR(ActionMoveBy);
KGE_DECLARE_SMART_PTR(ActionMoveTo);
KGE_DECLARE_SMART_PTR(ActionJumpBy);
KGE_DECLARE_SMART_PTR(ActionJumpTo);
KGE_DECLARE_SMART_PTR(ActionScaleBy);
KGE_DECLARE_SMART_PTR(ActionScaleTo);
KGE_DECLARE_SMART_PTR(ActionFadeTo);
KGE_DECLARE_SMART_PTR(ActionFadeIn);
KGE_DECLARE_SMART_PTR(ActionFadeOut);
KGE_DECLARE_SMART_PTR(ActionRotateBy);
KGE_DECLARE_SMART_PTR(ActionRotateTo);
KGE_DECLARE_SMART_PTR(ActionCustom);
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 补间动画
class KGE_API ActionTween : public Action
{
public:
ActionTween();
/// \~chinese
/// @brief 补间动画
/// @param duration 动画时长
/// @param func 动画速度缓动函数
ActionTween(Duration duration, EaseFunc func);
/// \~chinese
/// @brief 获取动画时长
Duration GetDuration() const;
/// \~chinese
/// @brief 设置动画时长
void SetDuration(Duration duration);
/// \~chinese
/// @brief 获取动画速度缓动函数
EaseFunc const& GetEaseFunc() const;
/// \~chinese
/// @brief 设置动画速度缓动函数
void SetEaseFunc(EaseFunc const& func);
protected:
void Update(Actor* target, Duration dt) override;
virtual void UpdateTween(Actor* target, float percent) = 0;
private:
Duration dur_;
EaseFunc ease_func_;
};
/// \~chinese
/// @brief 相对位移动画
class KGE_API ActionMoveBy : public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对位移动画
/// @param duration 动画时长
/// @param vector 移动向量
/// @param func 动画速度缓动函数
ActionMoveBy(Duration duration, Vec2 const& vector, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
Point start_pos_;
Point prev_pos_;
Vec2 delta_pos_;
};
/// \~chinese
/// @brief 位移动画
class KGE_API ActionMoveTo : public ActionMoveBy
{
public:
/// \~chinese
/// @brief 构造位移动画
/// @param duration 动画时长
/// @param pos 目的坐标
/// @param func 动画速度缓动函数
ActionMoveTo(Duration duration, Point const& pos, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionMoveTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
Point end_pos_;
};
/// \~chinese
/// @brief 相对跳跃动画
class KGE_API ActionJumpBy : public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对跳跃动画
/// @param duration 动画时长
/// @param vec 跳跃位移向量
/// @param height 跳跃高度
/// @param jumps 跳跃次数
/// @param func 动画速度缓动函数
ActionJumpBy(Duration duration, Vec2 const& vec, float height, int jumps = 1, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
Point start_pos_;
Point delta_pos_;
float height_;
int jumps_;
Point prev_pos_;
};
/// \~chinese
/// @brief 跳跃动画
class KGE_API ActionJumpTo : public ActionJumpBy
{
public:
/// \~chinese
/// @brief 构造跳跃动画
/// @param duration 动画时长
/// @param pos 目的坐标
/// @param height 跳跃高度
/// @param jumps 跳跃次数
/// @param func 动画速度缓动函数
ActionJumpTo(Duration duration, Point const& pos, float height, int jumps = 1, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionJumpTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
Point end_pos_;
};
/// \~chinese
/// @brief 相对缩放动画
class KGE_API ActionScaleBy : public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放相对变化值
/// @param scale_y 纵向缩放相对变化值
/// @param func 动画速度缓动函数
ActionScaleBy(Duration duration, float scale_x, float scale_y, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
float start_scale_x_;
float start_scale_y_;
float delta_x_;
float delta_y_;
};
/// \~chinese
/// @brief 缩放动画
class KGE_API ActionScaleTo : public ActionScaleBy
{
public:
/// \~chinese
/// @brief 构造缩放动画
/// @param duration 动画时长
/// @param scale_x 横向缩放目标值
/// @param scale_y 纵向缩放目标值
/// @param func 动画速度缓动函数
ActionScaleTo(Duration duration, float scale_x, float scale_y, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionScaleTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
float end_scale_x_;
float end_scale_y_;
};
/// \~chinese
/// @brief 透明度渐变动画
class KGE_API ActionFadeTo : public ActionTween
{
public:
/// \~chinese
/// @brief 构造透明度渐变动画
/// @param duration 动画时长
/// @param opacity 目标透明度
/// @param func 动画速度缓动函数
ActionFadeTo(Duration duration, float opacity, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionFadeTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
private:
float start_val_;
float delta_val_;
float end_val_;
};
/// \~chinese
/// @brief 淡入动画
class KGE_API ActionFadeIn : public ActionFadeTo
{
public:
/// \~chinese
/// @brief 构造淡入动画
/// @param duration 动画时长
/// @param func 动画速度缓动函数
explicit ActionFadeIn(Duration duration, EaseFunc func = nullptr);
};
/// \~chinese
/// @brief 淡出动画
class KGE_API ActionFadeOut : public ActionFadeTo
{
public:
/// \~chinese
/// @brief 构造淡出动画
/// @param duration 动画时长
/// @param func 动画速度缓动函数
explicit ActionFadeOut(Duration duration, EaseFunc func = nullptr);
};
/// \~chinese
/// @brief 相对旋转动画
class KGE_API ActionRotateBy : public ActionTween
{
public:
/// \~chinese
/// @brief 构造相对旋转动画
/// @param duration 动画时长
/// @param rotation 角度相对变化值
/// @param func 动画速度缓动函数
ActionRotateBy(Duration duration, float rotation, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
protected:
float start_val_;
float delta_val_;
};
/// \~chinese
/// @brief 旋转动画
class KGE_API ActionRotateTo : public ActionRotateBy
{
public:
/// \~chinese
/// @brief 构造旋转动画
/// @param duration 动画时长
/// @param rotation 目标角度
/// @param func 动画速度缓动函数
ActionRotateTo(Duration duration, float rotation, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionRotateTo");
return nullptr;
}
protected:
void Init(Actor* target) override;
private:
float end_val_;
};
/// \~chinese
/// @brief 自定义动画
class KGE_API ActionCustom : public ActionTween
{
public:
/// \~chinese
/// @brief 动画回调函数
/// @details 在动画更新时回调该函数第一个参数是执行动画的目标第二个参数是动画进度0.0 - 1.0
using TweenFunc = Function<void(Actor* /* target */, float /* percent */)>;
/// \~chinese
/// @brief 构造自定义动画
/// @param duration 动画时长
/// @param tween_func 动画回调函数
/// @param func 动画速度缓动函数
ActionCustom(Duration duration, TweenFunc tween_func, EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override
{
KGE_ERROR(L"Reverse() not supported in ActionCustom");
return nullptr;
}
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
private:
TweenFunc tween_func_;
};
/** @} */
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,110 +18,110 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/2d/action/ActionWalk.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/action/ActionWalk.h>
namespace kiwano
{
ActionWalk::ActionWalk(Duration duration, bool rotating, float start, float end, EaseFunc func)
: ActionTween(duration, func)
, start_(start)
, end_(end)
, rotating_(rotating)
, length_(0.f)
{
}
ActionWalk::ActionWalk(Duration duration, Geometry const& path, bool rotating, float start, float end, EaseFunc func)
: ActionWalk(duration, rotating, start, end, func)
{
path_ = path;
}
ActionPtr ActionWalk::Clone() const
{
ActionWalkPtr clone = new ActionWalk(GetDuration(), rotating_, start_, end_, GetEaseFunc());
if (clone)
{
clone->SetPath(path_);
}
return clone;
}
ActionPtr ActionWalk::Reverse() const
{
ActionWalkPtr reverse = new ActionWalk(GetDuration(), rotating_, end_, start_, GetEaseFunc());
if (reverse)
{
reverse->SetPath(path_);
}
return reverse;
}
void ActionWalk::Init(Actor* target)
{
if (!path_.IsValid())
{
Done();
return;
}
start_pos_ = target->GetPosition();
length_ = path_.GetLength();
}
void ActionWalk::UpdateTween(Actor* target, float percent)
{
float distance = length_ * std::min(std::max((end_ - start_) * percent + start_, 0.f), 1.f);
Point point, tangent;
if (path_.ComputePointAtLength(distance, point, tangent))
{
target->SetPosition(start_pos_ + point);
if (rotating_)
{
float ac = math::Acos(tangent.x);
float rotation = (tangent.y < 0.f) ? 360.f - ac : ac;
target->SetRotation(rotation);
}
}
}
void ActionWalk::BeginPath()
{
sink_.BeginPath();
}
void ActionWalk::EndPath(bool closed)
{
sink_.EndPath(closed);
path_ = sink_.GetGeometry();
}
void ActionWalk::AddLine(Point const& point)
{
sink_.AddLine(point);
}
void ActionWalk::AddLines(Vector<Point> const& points)
{
sink_.AddLines(points);
}
void ActionWalk::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
sink_.AddBezier(point1, point2, point3);
}
void ActionWalk::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
sink_.AddArc(point, radius, rotation, clockwise, is_small);
}
void ActionWalk::ClearPath()
{
path_.Clear();
}
ActionWalk::ActionWalk(Duration duration, bool rotating, float start, float end, EaseFunc func)
: ActionTween(duration, func)
, start_(start)
, end_(end)
, rotating_(rotating)
, length_(0.f)
{
}
ActionWalk::ActionWalk(Duration duration, Geometry const& path, bool rotating, float start, float end, EaseFunc func)
: ActionWalk(duration, rotating, start, end, func)
{
path_ = path;
}
ActionPtr ActionWalk::Clone() const
{
ActionWalkPtr clone = new ActionWalk(GetDuration(), rotating_, start_, end_, GetEaseFunc());
if (clone)
{
clone->SetPath(path_);
}
return clone;
}
ActionPtr ActionWalk::Reverse() const
{
ActionWalkPtr reverse = new ActionWalk(GetDuration(), rotating_, end_, start_, GetEaseFunc());
if (reverse)
{
reverse->SetPath(path_);
}
return reverse;
}
void ActionWalk::Init(Actor* target)
{
if (!path_.IsValid())
{
Done();
return;
}
start_pos_ = target->GetPosition();
length_ = path_.GetLength();
}
void ActionWalk::UpdateTween(Actor* target, float percent)
{
float distance = length_ * std::min(std::max((end_ - start_) * percent + start_, 0.f), 1.f);
Point point, tangent;
if (path_.ComputePointAtLength(distance, point, tangent))
{
target->SetPosition(start_pos_ + point);
if (rotating_)
{
float ac = math::Acos(tangent.x);
float rotation = (tangent.y < 0.f) ? 360.f - ac : ac;
target->SetRotation(rotation);
}
}
}
void ActionWalk::BeginPath()
{
sink_.BeginPath();
}
void ActionWalk::EndPath(bool closed)
{
sink_.EndPath(closed);
path_ = sink_.GetGeometry();
}
void ActionWalk::AddLine(Point const& point)
{
sink_.AddLine(point);
}
void ActionWalk::AddLines(Vector<Point> const& points)
{
sink_.AddLines(points);
}
void ActionWalk::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
sink_.AddBezier(point1, point2, point3);
}
void ActionWalk::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
sink_.AddArc(point, radius, rotation, clockwise, is_small);
}
void ActionWalk::ClearPath()
{
path_.Clear();
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -25,112 +25,118 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(ActionWalk);
KGE_DECLARE_SMART_PTR(ActionWalk);
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 路径行走动画
class KGE_API ActionWalk
: public ActionTween
{
public:
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
/// @param func 动画速度缓动函数
ActionWalk(Duration duration, bool rotating = false, float start = 0.f, float end = 1.f, EaseFunc func = nullptr);
/// \~chinese
/// @brief 路径行走动画
class KGE_API ActionWalk : public ActionTween
{
public:
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
/// @param func 动画速度缓动函数
ActionWalk(Duration duration, bool rotating = false, float start = 0.f, float end = 1.f, EaseFunc func = nullptr);
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param path 路径几何形状
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
/// @param func 动画速度缓动函数
ActionWalk(Duration duration, Geometry const& path, bool rotating = false, float start = 0.f, float end = 1.f, EaseFunc func = nullptr);
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param path 路径几何形状
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @param end 路径终点(百分比)
/// @param func 动画速度缓动函数
ActionWalk(Duration duration, Geometry const& path, bool rotating = false, float start = 0.f, float end = 1.f,
EaseFunc func = nullptr);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
/// \~chinese
/// @brief 开始添加路线
void BeginPath();
/// \~chinese
/// @brief 开始添加路线
void BeginPath();
/// \~chinese
/// @brief 结束路线
/// @param closed 路线是否闭合
void EndPath(bool closed = false);
/// \~chinese
/// @brief 结束路线
/// @param closed 路线是否闭合
void EndPath(bool closed = false);
/// \~chinese
/// @brief 添加一条线段
/// @param point 线段端点
void AddLine(Point const& point);
/// \~chinese
/// @brief 添加一条线段
/// @param point 线段端点
void AddLine(Point const& point);
/// \~chinese
/// @brief 添加多条线段
/// @param points 端点集合
void AddLines(Vector<Point> const& points);
/// \~chinese
/// @brief 添加多条线段
/// @param points 端点集合
void AddLines(Vector<Point> const& points);
/// \~chinese
/// @brief 添加一条三次方贝塞尔曲线
/// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
/// \~chinese
/// @brief 添加一条三次方贝塞尔曲线
/// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
/// \~chinese
/// @brief 添加弧线
/// @param point 椭圆圆心
/// @param radius 椭圆半径
/// @param rotation 椭圆旋转角度
/// @param clockwise 顺时针 or 逆时针
/// @param is_small 是否取小于 180° 的弧
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
/// \~chinese
/// @brief 添加弧线
/// @param point 椭圆圆心
/// @param radius 椭圆半径
/// @param rotation 椭圆旋转角度
/// @param clockwise 顺时针 or 逆时针
/// @param is_small 是否取小于 180° 的弧
void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true);
/// \~chinese
/// @brief 清除路径
void ClearPath();
/// \~chinese
/// @brief 清除路径
void ClearPath();
/// \~chinese
/// @brief 获取路线
Geometry const& GetPath() const;
/// \~chinese
/// @brief 获取路线
Geometry const& GetPath() const;
/// \~chinese
/// @brief 设置路径几何形状
void SetPath(Geometry const& path);
/// \~chinese
/// @brief 设置路径几何形状
void SetPath(Geometry const& path);
protected:
void Init(Actor* target) override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
void UpdateTween(Actor* target, float percent) override;
private:
bool rotating_;
float start_;
float end_;
float length_;
Point start_pos_;
Geometry path_;
GeometrySink sink_;
};
private:
bool rotating_;
float start_;
float end_;
float length_;
Point start_pos_;
Geometry path_;
GeometrySink sink_;
};
/** @} */
/** @} */
inline Geometry const& ActionWalk::GetPath() const { return path_; }
inline void ActionWalk::SetPath(Geometry const& path) { path_ = path; }
inline Geometry const& ActionWalk::GetPath() const
{
return path_;
}
inline void ActionWalk::SetPath(Geometry const& path)
{
path_ = path;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,90 +18,88 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/2d/action/Animation.h>
#include <kiwano/2d/FrameSequence.h>
#include <kiwano/2d/Sprite.h>
#include <kiwano/2d/action/Animation.h>
namespace kiwano
{
Animation::Animation()
: frame_seq_(nullptr)
{
}
Animation::Animation(Duration duration, FrameSequencePtr frame_seq, EaseFunc func)
: ActionTween(duration, func)
, frame_seq_(nullptr)
{
this->SetFrameSequence(frame_seq);
}
Animation::~Animation()
{
}
FrameSequencePtr Animation::GetFrameSequence() const
{
return frame_seq_;
}
void Animation::SetFrameSequence(FrameSequencePtr frame_seq)
{
frame_seq_ = frame_seq;
}
void Animation::Init(Actor* target)
{
KGE_ASSERT(frame_seq_ && "Animation::Init() failed: FrameSequence is NULL!");
if (!frame_seq_ || frame_seq_->GetFrames().empty())
{
Done();
return;
}
auto sprite_target = dynamic_cast<Sprite*>(target);
KGE_ASSERT(sprite_target && "Animation only supports Sprites!");
if (sprite_target && frame_seq_)
{
sprite_target->SetFrame(frame_seq_->GetFrames()[0]);
}
}
void Animation::UpdateTween(Actor* target, float percent)
{
auto sprite_target = dynamic_cast<Sprite*>(target);
if (sprite_target && frame_seq_)
{
const auto& frames = frame_seq_->GetFrames();
auto size = frames.size();
auto index = std::min(static_cast<size_t>(math::Floor(size * percent)), size - 1);
sprite_target->SetFrame(frames[index]);
}
}
ActionPtr Animation::Clone() const
{
if (frame_seq_)
{
return new (std::nothrow) Animation(GetDuration(), frame_seq_, GetEaseFunc());
}
return nullptr;
}
ActionPtr Animation::Reverse() const
{
if (frame_seq_)
{
FrameSequencePtr frames = frame_seq_->Reverse();
if (frames)
{
return new (std::nothrow) Animation(GetDuration(), frames, GetEaseFunc());
}
}
return nullptr;
}
Animation::Animation()
: frame_seq_(nullptr)
{
}
Animation::Animation(Duration duration, FrameSequencePtr frame_seq, EaseFunc func)
: ActionTween(duration, func)
, frame_seq_(nullptr)
{
this->SetFrameSequence(frame_seq);
}
Animation::~Animation() {}
FrameSequencePtr Animation::GetFrameSequence() const
{
return frame_seq_;
}
void Animation::SetFrameSequence(FrameSequencePtr frame_seq)
{
frame_seq_ = frame_seq;
}
void Animation::Init(Actor* target)
{
KGE_ASSERT(frame_seq_ && "Animation::Init() failed: FrameSequence is NULL!");
if (!frame_seq_ || frame_seq_->GetFrames().empty())
{
Done();
return;
}
auto sprite_target = dynamic_cast<Sprite*>(target);
KGE_ASSERT(sprite_target && "Animation only supports Sprites!");
if (sprite_target && frame_seq_)
{
sprite_target->SetFrame(frame_seq_->GetFrames()[0]);
}
}
void Animation::UpdateTween(Actor* target, float percent)
{
auto sprite_target = dynamic_cast<Sprite*>(target);
if (sprite_target && frame_seq_)
{
const auto& frames = frame_seq_->GetFrames();
auto size = frames.size();
auto index = std::min(static_cast<size_t>(math::Floor(size * percent)), size - 1);
sprite_target->SetFrame(frames[index]);
}
}
ActionPtr Animation::Clone() const
{
if (frame_seq_)
{
return new (std::nothrow) Animation(GetDuration(), frame_seq_, GetEaseFunc());
}
return nullptr;
}
ActionPtr Animation::Reverse() const
{
if (frame_seq_)
{
FrameSequencePtr frames = frame_seq_->Reverse();
if (frames)
{
return new (std::nothrow) Animation(GetDuration(), frames, GetEaseFunc());
}
}
return nullptr;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,60 +19,59 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/2d/action/ActionTween.h>
#include <kiwano/2d/FrameSequence.h>
#include <kiwano/2d/action/ActionTween.h>
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Animation);
KGE_DECLARE_SMART_PTR(Animation);
/**
* \addtogroup Actions
* @{
*/
/**
* \addtogroup Actions
* @{
*/
/// \~chinese
/// @brief 帧动画
class KGE_API Animation
: public ActionTween
{
public:
Animation();
/// \~chinese
/// @brief 帧动画
class KGE_API Animation : public ActionTween
{
public:
Animation();
/// \~chinese
/// @brief 构建帧动画
/// @param duration 动画时长
/// @param[in] frame_seq 序列帧
/// @param func 动画速度缓动函数
Animation(Duration duration, FrameSequencePtr frame_seq, EaseFunc func = nullptr);
/// \~chinese
/// @brief 构建帧动画
/// @param duration 动画时长
/// @param[in] frame_seq 序列帧
/// @param func 动画速度缓动函数
Animation(Duration duration, FrameSequencePtr frame_seq, EaseFunc func = nullptr);
virtual ~Animation();
virtual ~Animation();
/// \~chinese
/// @brief 获取序列帧
FrameSequencePtr GetFrameSequence() const;
/// \~chinese
/// @brief 获取序列帧
FrameSequencePtr GetFrameSequence() const;
/// \~chinese
/// @brief 设置序列帧
/// @param[in] frame_seq 序列帧
void SetFrameSequence(FrameSequencePtr frame_seq);
/// \~chinese
/// @brief 设置序列帧
/// @param[in] frame_seq 序列帧
void SetFrameSequence(FrameSequencePtr frame_seq);
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的拷贝对象
ActionPtr Clone() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
/// \~chinese
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override;
protected:
void Init(Actor* target) override;
protected:
void Init(Actor* target) override;
void UpdateTween(Actor* target, float percent) override;
void UpdateTween(Actor* target, float percent) override;
private:
FrameSequencePtr frame_seq_;
};
private:
FrameSequencePtr frame_seq_;
};
/** @} */
}
/** @} */
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -23,69 +23,67 @@
namespace kiwano
{
AsyncTask::AsyncTask()
: thread_(Closure(this, &AsyncTask::TaskThread))
{
}
AsyncTask::AsyncTask(AsyncTaskFunc func)
: AsyncTask()
{
Then(func);
}
AsyncTask::~AsyncTask()
{
}
void AsyncTask::Start()
{
thread_.detach();
// retain this object until finished
Retain();
}
AsyncTask& AsyncTask::Then(AsyncTaskFunc func)
{
std::lock_guard<std::mutex> lock(func_mutex_);
thread_func_queue_.push(func);
return (*this);
}
AsyncTask& AsyncTask::SetCallback(AsyncTaskCallback callback)
{
thread_cb_ = callback;
return (*this);
}
void AsyncTask::TaskThread()
{
while (!thread_func_queue_.empty())
{
auto& func = thread_func_queue_.front();
if (func)
{
func();
}
func_mutex_.lock();
thread_func_queue_.pop();
func_mutex_.unlock();
}
Application::PreformInMainThread(Closure(this, &AsyncTask::Complete));
}
void AsyncTask::Complete()
{
if (thread_cb_)
{
thread_cb_();
}
// Release this object
Release();
}
AsyncTask::AsyncTask()
: thread_(Closure(this, &AsyncTask::TaskThread))
{
}
AsyncTask::AsyncTask(AsyncTaskFunc func)
: AsyncTask()
{
Then(func);
}
AsyncTask::~AsyncTask() {}
void AsyncTask::Start()
{
thread_.detach();
// retain this object until finished
Retain();
}
AsyncTask& AsyncTask::Then(AsyncTaskFunc func)
{
std::lock_guard<std::mutex> lock(func_mutex_);
thread_func_queue_.push(func);
return (*this);
}
AsyncTask& AsyncTask::SetCallback(AsyncTaskCallback callback)
{
thread_cb_ = callback;
return (*this);
}
void AsyncTask::TaskThread()
{
while (!thread_func_queue_.empty())
{
auto& func = thread_func_queue_.front();
if (func)
{
func();
}
func_mutex_.lock();
thread_func_queue_.pop();
func_mutex_.unlock();
}
Application::PreformInMainThread(Closure(this, &AsyncTask::Complete));
}
void AsyncTask::Complete()
{
if (thread_cb_)
{
thread_cb_();
}
// Release this object
Release();
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,69 +19,61 @@
// THE SOFTWARE.
#pragma once
#include <thread>
#include <mutex>
#include <kiwano/core/ObjectBase.h>
#include <mutex>
#include <thread>
namespace kiwano
{
KGE_DECLARE_SMART_PTR(AsyncTask);
KGE_DECLARE_SMART_PTR(AsyncTask);
typedef Function<void()> AsyncTaskFunc;
typedef Function<void()> AsyncTaskCallback;
typedef Function<void()> AsyncTaskFunc;
typedef Function<void()> AsyncTaskCallback;
/// \~chinese
/// @brief 异步任务
/// @details 在多线程下执行任务并返回
/// @code
/// AsyncTaskPtr task = new AsyncTask;
/// task->Then(DoSomething);
/// task->Start();
/// @endcode
class AsyncTask
: public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 构造异步任务
AsyncTask();
/// \~chinese
/// @brief 异步任务
/// @details 在多线程下执行任务并返回
/// @code
/// AsyncTaskPtr task = new AsyncTask;
/// task->Then(DoSomething);
/// task->Start();
/// @endcode
class AsyncTask : public virtual ObjectBase
{
public:
/// \~chinese
/// @brief 构造异步任务
AsyncTask();
/// \~chinese
/// @brief 构造异步任务
/// @param func 异步回调函数
AsyncTask(
AsyncTaskFunc func
);
/// \~chinese
/// @brief 构造异步任务
/// @param func 异步回调函数
AsyncTask(AsyncTaskFunc func);
virtual ~AsyncTask();
virtual ~AsyncTask();
/// \~chinese
/// @brief 添加异步任务链
AsyncTask& Then(
AsyncTaskFunc func
);
/// \~chinese
/// @brief 添加异步任务链
AsyncTask& Then(AsyncTaskFunc func);
/// \~chinese
/// @brief 设置任务执行完成后的回调函数
/// @note 该函数在 Kiwano 主线程中执行
AsyncTask& SetCallback(
AsyncTaskCallback callback
);
/// \~chinese
/// @brief 设置任务执行完成后的回调函数
/// @note 该函数在 Kiwano 主线程中执行
AsyncTask& SetCallback(AsyncTaskCallback callback);
/// \~chinese
/// @brief 启动异步任务
void Start();
/// \~chinese
/// @brief 启动异步任务
void Start();
private:
void TaskThread();
private:
void TaskThread();
void Complete();
void Complete();
private:
std::thread thread_;
std::mutex func_mutex_;
Queue<AsyncTaskFunc> thread_func_queue_;
AsyncTaskCallback thread_cb_;
};
}
private:
std::thread thread_;
std::mutex func_mutex_;
Queue<AsyncTaskFunc> thread_func_queue_;
AsyncTaskCallback thread_cb_;
};
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,144 +19,146 @@
// THE SOFTWARE.
#pragma once
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <unordered_set>
#include <unordered_map>
#include <sstream>
#include <3rd-party/OuterC/oc/oc.h>
#include <kiwano/macros.h>
#include <kiwano/core/Singleton.h>
#include <kiwano/macros.h>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <unordered_map>
#include <unordered_set>
namespace kiwano
{
/// \~chinese
/// @brief 字符串容器
using String = oc::wstring;
/// \~chinese
/// @brief 字符串容器
using String = oc::wstring;
/// \~chinese
/// @brief 窄字符串容器
using ByteString = oc::string;
/// \~chinese
/// @brief 窄字符串容器
using ByteString = oc::string;
/// \~chinese
/// @brief 字符串流
using StringStream = std::wstringstream;
/// \~chinese
/// @brief 字符串流
using StringStream = std::wstringstream;
/// \~chinese
/// @brief 线性数组容器
template <typename _Ty, typename... _Args>
using Vector = oc::vector<_Ty, _Args...>;
/// \~chinese
/// @brief 线性数组容器
template <typename _Ty, typename... _Args>
using Vector = oc::vector<_Ty, _Args...>;
/// \~chinese
/// @brief 链表容器
template <typename _Ty, typename... _Args>
using List = std::list<_Ty, _Args...>;
/// \~chinese
/// @brief 链表容器
template <typename _Ty, typename... _Args>
using List = std::list<_Ty, _Args...>;
/// \~chinese
/// @brief 队列容器
template <typename _Ty, typename... _Args>
using Queue = std::queue<_Ty, _Args...>;
/// \~chinese
/// @brief 队列容器
template <typename _Ty, typename... _Args>
using Queue = std::queue<_Ty, _Args...>;
/// \~chinese
/// @brief 集合容器
template <typename _Ty, typename... _Args>
using Set = std::set<_Ty, _Args...>;
/// \~chinese
/// @brief 集合容器
template <typename _Ty, typename... _Args>
using Set = std::set<_Ty, _Args...>;
/// \~chinese
/// @brief 对容器
template <typename _Ty1, typename _Ty2>
using Pair = std::pair<_Ty1, _Ty2>;
/// \~chinese
/// @brief 对容器
template <typename _Ty1, typename _Ty2>
using Pair = std::pair<_Ty1, _Ty2>;
/// \~chinese
/// @brief 无序集合容器
template <typename _Ty, typename... _Args>
using UnorderedSet = std::unordered_set<_Ty, _Args...>;
/// \~chinese
/// @brief 无序集合容器
template <typename _Ty, typename... _Args>
using UnorderedSet = std::unordered_set<_Ty, _Args...>;
/// \~chinese
/// @brief 栈容器
template <typename _Ty, typename... _Args>
using Stack = std::stack<_Ty, _Args...>;
/// \~chinese
/// @brief 栈容器
template <typename _Ty, typename... _Args>
using Stack = std::stack<_Ty, _Args...>;
/// \~chinese
/// @brief 字符串容器
template <typename _Kty, typename _Ty, typename... _Args>
using Map = std::map<_Kty, _Ty, _Args...>;
/// \~chinese
/// @brief 字符串容器
template <typename _Kty, typename _Ty, typename... _Args>
using Map = std::map<_Kty, _Ty, _Args...>;
/// \~chinese
/// @brief 字符串容器
template <typename _Kty, typename _Ty, typename... _Args>
using UnorderedMap = std::unordered_map<_Kty, _Ty, _Args...>;
/// \~chinese
/// @brief 字符串容器
template <typename _Kty, typename _Ty, typename... _Args>
using UnorderedMap = std::unordered_map<_Kty, _Ty, _Args...>;
/// \~chinese
/// @brief 函数封装器
/// @par
/// 使用函数封装器可以储存、复制和调用任何可调用目标,示例代码如下:
/// @code
/// Function<bool(int)> func1 = StaticFunc; // bool StaticFunc(int x);
/// Function<bool(int)> func2 = Closure(&t, &T::Func); // bool T::Func(int x);
/// Function<bool(int)> func3 = T::StaticFunc; // static bool T::StaticFunc(int x);
/// Function<bool(int)> func4 = [](int x) -> bool {}; // Lambda function
/// Function<bool(int)> func5 = std::bind(&T::Func, &t); // std::bind
/// Function<bool(int)> func5 = Callable(); // Callable objects: struct Callable { bool operator()(int x) {} };
/// @endcode
template <typename _FuncTy>
using Function = oc::function<_FuncTy>;
/// \~chinese
/// @brief 函数封装器
/// @par
/// 使用函数封装器可以储存、复制和调用任何可调用目标,示例代码如下:
/// @code
/// Function<bool(int)> func1 = StaticFunc; // bool
/// StaticFunc(int x);
/// Function<bool(int)> func2 = Closure(&t, &T::Func); // bool
/// T::Func(int x);
/// Function<bool(int)> func3 = T::StaticFunc; // static bool
/// T::StaticFunc(int x);
/// Function<bool(int)> func4 = [](int x) -> bool {}; // Lambda function
/// Function<bool(int)> func5 = std::bind(&T::Func, &t); // std::bind
/// Function<bool(int)> func5 = Callable(); // Callable
/// objects: struct Callable { bool operator()(int x) {} };
/// @endcode
template <typename _FuncTy>
using Function = oc::function<_FuncTy>;
/// \~chinese
/// @brief 单值容器
using Any = oc::any;
/// \~chinese
/// @brief 单值容器
using Any = oc::any;
/// \~chinese
/// @brief JSON对象容器
using Json = oc::basic_json<Map, Vector, String, int, double, bool, std::allocator>;
/// \~chinese
/// @brief JSON对象容器
using Json = oc::basic_json<Map, Vector, String, int, double, bool, std::allocator>;
/// \~chinese
/// @brief 侵入式链表容器
template <typename _Ty>
using IntrusiveList = oc::intrusive_list<_Ty>;
/// \~chinese
/// @brief 侵入式链表容器
template <typename _Ty>
using IntrusiveList = oc::intrusive_list<_Ty>;
/// \~chinese
/// @brief 侵入式链表元素
template <typename _Ty>
using IntrusiveListItem = oc::intrusive_list_item<_Ty>;
/// \~chinese
/// @brief 侵入式链表元素
template <typename _Ty>
using IntrusiveListItem = oc::intrusive_list_item<_Ty>;
/// \~chinese
/// @brief 侵入式智能指针
template <typename _Ty, typename _RefProxyTy>
using IntrusivePtr = oc::intrusive_ptr<_Ty, _RefProxyTy>;
/// \~chinese
/// @brief 侵入式智能指针
template <typename _Ty, typename _RefProxyTy>
using IntrusivePtr = oc::intrusive_ptr<_Ty, _RefProxyTy>;
/// \~chinese
/// @brief 不可拷贝对象
using Noncopyable = oc::noncopyable;
/// \~chinese
/// @brief 不可拷贝对象
using Noncopyable = oc::noncopyable;
/// \~chinese
/// @brief 闭包函数
template<typename _Ty, typename _Uty, typename _Ret, typename... _Args>
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...))
{
return oc::closure(ptr, func);
}
/// \~chinese
/// @brief 闭包函数
template<typename _Ty, typename _Uty, typename _Ret, typename... _Args>
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const)
{
return oc::closure(ptr, func);
}
inline ByteString WideToMultiByte(const String& str)
{
return oc::wide_to_string(str);
}
inline String MultiByteToWide(const ByteString& str)
{
return oc::string_to_wide(str);
}
/// \~chinese
/// @brief 闭包函数
template <typename _Ty, typename _Uty, typename _Ret, typename... _Args>
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...))
{
return oc::closure(ptr, func);
}
/// \~chinese
/// @brief 闭包函数
template <typename _Ty, typename _Uty, typename _Ret, typename... _Args>
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...) const)
{
return oc::closure(ptr, func);
}
inline ByteString WideToMultiByte(const String& str)
{
return oc::wide_to_string(str);
}
inline String MultiByteToWide(const ByteString& str)
{
return oc::string_to_wide(str);
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -20,37 +20,37 @@
#include <kiwano/core/Component.h>
#define KGE_DEFINE_COMPONENT_FLAG(OFFSET) ( 0x01 << (OFFSET % 32) )
#define KGE_DEFINE_COMPONENT_FLAG(OFFSET) (0x01 << (OFFSET % 32))
namespace kiwano
{
const int RenderComponent::flag = KGE_DEFINE_COMPONENT_FLAG(0);
const int UpdateComponent::flag = KGE_DEFINE_COMPONENT_FLAG(1);
const int EventComponent::flag = KGE_DEFINE_COMPONENT_FLAG(2);
ComponentBase::ComponentBase()
: flag_(0)
{
}
bool ComponentBase::Check(const int flag)
{
return !!(flag_ & flag);
}
RenderComponent::RenderComponent()
{
flag_ |= flag;
}
UpdateComponent::UpdateComponent()
{
flag_ |= flag;
}
EventComponent::EventComponent()
{
flag_ |= flag;
}
const int RenderComponent::flag = KGE_DEFINE_COMPONENT_FLAG(0);
const int UpdateComponent::flag = KGE_DEFINE_COMPONENT_FLAG(1);
const int EventComponent::flag = KGE_DEFINE_COMPONENT_FLAG(2);
ComponentBase::ComponentBase()
: flag_(0)
{
}
bool ComponentBase::Check(const int flag)
{
return !!(flag_ & flag);
}
RenderComponent::RenderComponent()
{
flag_ |= flag;
}
UpdateComponent::UpdateComponent()
{
flag_ |= flag;
}
EventComponent::EventComponent()
{
flag_ |= flag;
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,112 +19,105 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/macros.h>
#include <kiwano/core/Time.h>
#include <kiwano/macros.h>
namespace kiwano
{
class RenderContext;
class Event;
class RenderContext;
class Event;
/**
* \~chinese
* @brief
*/
class KGE_API ComponentBase
{
public:
/// \~chinese
/// @brief 启动组件
virtual void SetupComponent() = 0;
/**
* \~chinese
* @brief
*/
class KGE_API ComponentBase
{
public:
/// \~chinese
/// @brief 启动组件
virtual void SetupComponent() = 0;
/// \~chinese
/// @brief 销毁组件
virtual void DestroyComponent() = 0;
/// \~chinese
/// @brief 销毁组件
virtual void DestroyComponent() = 0;
bool Check(const int flag);
bool Check(const int flag);
protected:
ComponentBase();
protected:
ComponentBase();
protected:
int flag_;
};
protected:
int flag_;
};
/**
* \~chinese
* @brief
*/
class KGE_API RenderComponent : public virtual ComponentBase
{
public:
/// \~chinese
/// @brief 渲染前
virtual void BeforeRender() {}
/**
* \~chinese
* @brief
*/
class KGE_API RenderComponent
: public virtual ComponentBase
{
public:
/// \~chinese
/// @brief 渲染前
virtual void BeforeRender() {}
/// \~chinese
/// @brief 渲染时
/// @param ctx 渲染上下文
virtual void OnRender(RenderContext& ctx) {}
/// \~chinese
/// @brief 渲染时
/// @param ctx 渲染上下文
virtual void OnRender(RenderContext& ctx) {}
/// \~chinese
/// @brief 渲染后
virtual void AfterRender() {}
/// \~chinese
/// @brief 渲染后
virtual void AfterRender() {}
public:
static const int flag;
public:
static const int flag;
RenderComponent();
};
RenderComponent();
};
/**
* \~chinese
* @brief
*/
class KGE_API UpdateComponent : public virtual ComponentBase
{
public:
/// \~chinese
/// @brief 更新前
virtual void BeforeUpdate() {}
/// \~chinese
/// @brief 更新时
/// @param dt 间隔时间
virtual void OnUpdate(Duration dt) {}
/**
* \~chinese
* @brief
*/
class KGE_API UpdateComponent
: public virtual ComponentBase
{
public:
/// \~chinese
/// @brief 更新前
virtual void BeforeUpdate() {}
/// \~chinese
/// @brief 更新后
virtual void AfterUpdate() {}
/// \~chinese
/// @brief 更新时
/// @param dt 间隔时间
virtual void OnUpdate(Duration dt) {}
public:
static const int flag;
/// \~chinese
/// @brief 更新后
virtual void AfterUpdate() {}
UpdateComponent();
};
public:
static const int flag;
/**
* \~chinese
* @brief
*/
class KGE_API EventComponent : public virtual ComponentBase
{
public:
/// \~chinese
/// @brief 事件处理
/// @param evt 事件
virtual void HandleEvent(Event* evt) {}
UpdateComponent();
};
public:
static const int flag;
/**
* \~chinese
* @brief
*/
class KGE_API EventComponent
: public virtual ComponentBase
{
public:
/// \~chinese
/// @brief 事件处理
/// @param evt 事件
virtual void HandleEvent(Event* evt) {}
public:
static const int flag;
EventComponent();
};
}
EventComponent();
};
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -18,174 +18,172 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/core/Director.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/DebugActor.h>
#include <kiwano/2d/Stage.h>
#include <kiwano/2d/Transition.h>
#include <kiwano/2d/DebugActor.h>
#include <kiwano/core/Director.h>
#include <kiwano/render/RenderContext.h>
namespace kiwano
{
Director::Director()
: render_border_enabled_(false)
{
}
Director::~Director()
{
}
void Director::EnterStage(StagePtr stage, TransitionPtr transition)
{
KGE_ASSERT(stage && "Director::EnterStage failed, NULL pointer exception");
if (current_stage_ == stage || next_stage_ == stage)
return;
next_stage_ = stage;
if (transition && next_stage_)
{
if (transition_)
{
transition_->Stop();
}
transition_ = transition;
transition_->Init(current_stage_, next_stage_);
}
}
void Director::PushStage(StagePtr stage, TransitionPtr transition)
{
EnterStage(stage, transition);
if (current_stage_)
{
stages_.push(current_stage_);
}
}
void Director::PopStage(TransitionPtr transition)
{
KGE_ASSERT(!stages_.empty() && "Director::PopStage failed, calling pop() on empty stage stack");
if (!stages_.empty())
{
next_stage_ = stages_.top();
stages_.pop();
}
if (transition && next_stage_)
{
if (transition_)
{
transition_->Stop();
}
transition_ = transition;
transition_->Init(current_stage_, next_stage_);
}
}
StagePtr Director::GetCurrentStage()
{
return current_stage_;
}
void Director::SetRenderBorderEnabled(bool enabled)
{
render_border_enabled_ = enabled;
}
void Director::ShowDebugInfo(bool show)
{
if (show)
{
if (!debug_actor_)
debug_actor_ = new DebugActor;
}
else
{
debug_actor_.reset();
}
}
void Director::ClearStages()
{
while (!stages_.empty())
stages_.pop();
current_stage_.reset();
next_stage_.reset();
transition_.reset();
debug_actor_.reset();
}
void Director::OnUpdate(Duration dt)
{
if (transition_)
{
transition_->Update(dt);
if (transition_->IsDone())
transition_ = nullptr;
}
if (next_stage_ && !transition_)
{
if (current_stage_)
{
current_stage_->OnExit();
}
next_stage_->OnEnter();
current_stage_ = next_stage_;
next_stage_ = nullptr;
}
if (current_stage_)
current_stage_->Update(dt);
if (next_stage_)
next_stage_->Update(dt);
if (debug_actor_)
debug_actor_->Update(dt);
}
void Director::OnRender(RenderContext& ctx)
{
if (transition_)
{
transition_->Render(ctx);
}
else if (current_stage_)
{
current_stage_->Render(ctx);
if (render_border_enabled_)
{
current_stage_->RenderBorder(ctx);
}
}
if (debug_actor_)
{
debug_actor_->Render(ctx);
}
}
void Director::HandleEvent(Event* evt)
{
if (current_stage_)
current_stage_->DispatchEvent(evt);
if (next_stage_)
next_stage_->DispatchEvent(evt);
if (debug_actor_)
debug_actor_->DispatchEvent(evt);
}
Director::Director()
: render_border_enabled_(false)
{
}
Director::~Director() {}
void Director::EnterStage(StagePtr stage, TransitionPtr transition)
{
KGE_ASSERT(stage && "Director::EnterStage failed, NULL pointer exception");
if (current_stage_ == stage || next_stage_ == stage)
return;
next_stage_ = stage;
if (transition && next_stage_)
{
if (transition_)
{
transition_->Stop();
}
transition_ = transition;
transition_->Init(current_stage_, next_stage_);
}
}
void Director::PushStage(StagePtr stage, TransitionPtr transition)
{
EnterStage(stage, transition);
if (current_stage_)
{
stages_.push(current_stage_);
}
}
void Director::PopStage(TransitionPtr transition)
{
KGE_ASSERT(!stages_.empty() && "Director::PopStage failed, calling pop() on empty stage stack");
if (!stages_.empty())
{
next_stage_ = stages_.top();
stages_.pop();
}
if (transition && next_stage_)
{
if (transition_)
{
transition_->Stop();
}
transition_ = transition;
transition_->Init(current_stage_, next_stage_);
}
}
StagePtr Director::GetCurrentStage()
{
return current_stage_;
}
void Director::SetRenderBorderEnabled(bool enabled)
{
render_border_enabled_ = enabled;
}
void Director::ShowDebugInfo(bool show)
{
if (show)
{
if (!debug_actor_)
debug_actor_ = new DebugActor;
}
else
{
debug_actor_.reset();
}
}
void Director::ClearStages()
{
while (!stages_.empty())
stages_.pop();
current_stage_.reset();
next_stage_.reset();
transition_.reset();
debug_actor_.reset();
}
void Director::OnUpdate(Duration dt)
{
if (transition_)
{
transition_->Update(dt);
if (transition_->IsDone())
transition_ = nullptr;
}
if (next_stage_ && !transition_)
{
if (current_stage_)
{
current_stage_->OnExit();
}
next_stage_->OnEnter();
current_stage_ = next_stage_;
next_stage_ = nullptr;
}
if (current_stage_)
current_stage_->Update(dt);
if (next_stage_)
next_stage_->Update(dt);
if (debug_actor_)
debug_actor_->Update(dt);
}
void Director::OnRender(RenderContext& ctx)
{
if (transition_)
{
transition_->Render(ctx);
}
else if (current_stage_)
{
current_stage_->Render(ctx);
if (render_border_enabled_)
{
current_stage_->RenderBorder(ctx);
}
}
if (debug_actor_)
{
debug_actor_->Render(ctx);
}
}
void Director::HandleEvent(Event* evt)
{
if (current_stage_)
current_stage_->DispatchEvent(evt);
if (next_stage_)
next_stage_->DispatchEvent(evt);
if (debug_actor_)
debug_actor_->DispatchEvent(evt);
}
} // namespace kiwano

View File

@ -1,15 +1,15 @@
// 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
@ -19,108 +19,100 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/Component.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/Stage.h>
#include <kiwano/2d/Transition.h>
#include <kiwano/core/Component.h>
namespace kiwano
{
/**
* \~chinese
* @brief
* @details
* @see kiwano::Stage
*/
class KGE_API Director
: public Singleton<Director>
, public UpdateComponent
, public RenderComponent
, public EventComponent
{
friend Singleton<Director>;
/**
* \~chinese
* @brief
* @details
* @see kiwano::Stage
*/
class KGE_API Director
: public Singleton<Director>
, public UpdateComponent
, public RenderComponent
, public EventComponent
{
friend Singleton<Director>;
public:
/**
* \~chinese
* @brief
* @param[in] stage
* @param[in] transition
*/
void EnterStage(
StagePtr stage,
TransitionPtr transition = nullptr
);
public:
/**
* \~chinese
* @brief
* @param[in] stage
* @param[in] transition
*/
void EnterStage(StagePtr stage, TransitionPtr transition = nullptr);
/**
* \~chinese
* @brief
* @param[in] stage
* @param[in] transition
*/
void PushStage(
StagePtr stage,
TransitionPtr transition = nullptr
);
/**
* \~chinese
* @brief
* @param[in] stage
* @param[in] transition
*/
void PushStage(StagePtr stage, TransitionPtr transition = nullptr);
/**
* \~chinese
* @brief 退
* @param[in] transition
*/
void PopStage(
TransitionPtr transition = nullptr
);
/**
* \~chinese
* @brief 退
* @param[in] transition
*/
void PopStage(TransitionPtr transition = nullptr);
/**
* \~chinese
* @brief
* @return
*/
StagePtr GetCurrentStage();
/**
* \~chinese
* @brief
* @return
*/
StagePtr GetCurrentStage();
/**
* \~chinese
* @brief
* @param enabled
*/
void SetRenderBorderEnabled(bool enabled);
/**
* \~chinese
* @brief
* @param enabled
*/
void SetRenderBorderEnabled(bool enabled);
/**
* \~chinese
* @brief
* @param show
*/
void ShowDebugInfo(bool show = true);
/**
* \~chinese
* @brief
* @param show
*/
void ShowDebugInfo(bool show = true);
/**
* \~chinese
* @brief 退
*/
void ClearStages();
/**
* \~chinese
* @brief 退
*/
void ClearStages();
public:
void SetupComponent() override {}
public:
void SetupComponent() override {}
void DestroyComponent() override {}
void DestroyComponent() override {}
void OnUpdate(Duration dt) override;
void OnUpdate(Duration dt) override;
void OnRender(RenderContext& ctx) override;
void OnRender(RenderContext& ctx) override;
void HandleEvent(Event* evt) override;
void HandleEvent(Event* evt) override;
private:
Director();
private:
Director();
virtual ~Director();
virtual ~Director();
private:
bool render_border_enabled_;
Stack<StagePtr> stages_;
StagePtr current_stage_;
StagePtr next_stage_;
ActorPtr debug_actor_;
TransitionPtr transition_;
};
}
private:
bool render_border_enabled_;
Stack<StagePtr> stages_;
StagePtr current_stage_;
StagePtr next_stage_;
ActorPtr debug_actor_;
TransitionPtr transition_;
};
} // namespace kiwano

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