diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..f3202c42 --- /dev/null +++ b/.clang-format @@ -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 diff --git a/.editorconfig b/.editorconfig index 433e5b04..552be4bf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 \ No newline at end of file +indent_size = 2 diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index e829f7cc..a9cdfe46 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -65,13 +65,13 @@ - - - - - - - + + + + + + + @@ -136,11 +136,11 @@ - - - - - + + + + + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index dc22d2b5..4281032d 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -28,7 +28,7 @@ {adb44ca9-674a-4b77-993f-d65193d8ab06} - + {fd281702-0006-46d2-8fd1-28c502464164} @@ -222,27 +222,6 @@ core - - render\dx - - - render\dx - - - render\dx - - - render\dx - - - render\dx - - - render\dx - - - render\dx - render @@ -285,6 +264,27 @@ render + + render\DirectX + + + render\DirectX + + + render\DirectX + + + render\DirectX + + + render\DirectX + + + render\DirectX + + + render\DirectX + @@ -431,21 +431,6 @@ core - - render\dx - - - render\dx - - - render\dx - - - render\dx - - - render\dx - render @@ -485,5 +470,20 @@ render + + render\DirectX + + + render\DirectX + + + render\DirectX + + + render\DirectX + + + render\DirectX + \ No newline at end of file diff --git a/scripts/clang-format-all b/scripts/clang-format-all new file mode 100644 index 00000000..645c3ceb --- /dev/null +++ b/scripts/clang-format-all @@ -0,0 +1,84 @@ +#!/bin/bash +# +# clang-format-all: a tool to run clang-format on an entire project +# Copyright (C) 2016 Evan Klitzke +# +# 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 . + +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 diff --git a/src/kiwano-audio/AudioEngine.cpp b/src/kiwano-audio/AudioEngine.cpp index d060e31f..8e238f66 100644 --- a/src/kiwano-audio/AudioEngine.cpp +++ b/src/kiwano-audio/AudioEngine.cpp @@ -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 // win32::ThrowIfFailed -#include -#include #include +#include +#include +#include // 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 diff --git a/src/kiwano-audio/AudioEngine.h b/src/kiwano-audio/AudioEngine.h index 7a39c09a..fd877360 100644 --- a/src/kiwano-audio/AudioEngine.h +++ b/src/kiwano-audio/AudioEngine.h @@ -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 +#include #include #include -#include -#include #include namespace kiwano { - namespace audio - { - /** - * \~chinese - * \defgroup Audio 音频引擎 - */ +namespace audio +{ - /** - * \addtogroup Audio - * @{ - */ +/** + * \~chinese + * \defgroup Audio 音频引擎 + */ - /** - * \~chinese - * @brief 音频引擎 - */ - class KGE_API AudioEngine - : public Singleton - , public ComponentBase - { - friend Singleton; +/** + * \addtogroup Audio + * @{ + */ - public: - /// \~chinese - /// @brief 开启音频设备 - void Open(); +/** + * \~chinese + * @brief 音频引擎 + */ +class KGE_API AudioEngine + : public Singleton + , public ComponentBase +{ + friend Singleton; - /// \~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 diff --git a/src/kiwano-audio/Sound.cpp b/src/kiwano-audio/Sound.cpp index 88e6d056..39158d6b 100644 --- a/src/kiwano-audio/Sound.cpp +++ b/src/kiwano-audio/Sound.cpp @@ -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 +#include #include #include -#include -#include 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(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(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 diff --git a/src/kiwano-audio/Sound.h b/src/kiwano-audio/Sound.h index 61d40983..14987b15 100644 --- a/src/kiwano-audio/Sound.h +++ b/src/kiwano-audio/Sound.h @@ -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 #include #include #include -#include #include 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 diff --git a/src/kiwano-audio/SoundPlayer.cpp b/src/kiwano-audio/SoundPlayer.cpp index 5146b885..442a3e2a 100644 --- a/src/kiwano-audio/SoundPlayer.cpp +++ b/src/kiwano-audio/SoundPlayer.cpp @@ -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(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(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(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(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 diff --git a/src/kiwano-audio/SoundPlayer.h b/src/kiwano-audio/SoundPlayer.h index 523a37bc..df200860 100644 --- a/src/kiwano-audio/SoundPlayer.h +++ b/src/kiwano-audio/SoundPlayer.h @@ -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 #include +#include 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; - SoundMap sound_cache_; - }; + using SoundMap = Map; + SoundMap sound_cache_; +}; - /** @} */ - } -} +/** @} */ +} // namespace audio +} // namespace kiwano diff --git a/src/kiwano-audio/Transcoder.cpp b/src/kiwano-audio/Transcoder.cpp index d55b1a67..bef635c4 100644 --- a/src/kiwano-audio/Transcoder.cpp +++ b/src/kiwano-audio/Transcoder.cpp @@ -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 +#include +#include #include -#include #include +#include +#include #include #include -#include -#include 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 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 stream; - ComPtr byte_stream; - ComPtr reader; - - Resource::Data data = res.GetData(); - if (!data) { return E_FAIL; } - - stream = win32::dlls::Shlwapi::Get().SHCreateMemStream( - static_cast(data.buffer), - static_cast(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 partial_type; - ComPtr 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( - (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 sample; - ComPtr 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 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 stream; + ComPtr byte_stream; + ComPtr reader; + + Resource::Data data = res.GetData(); + if (!data) + { + return E_FAIL; + } + + stream = win32::dlls::Shlwapi::Get().SHCreateMemStream(static_cast(data.buffer), + static_cast(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 partial_type; + ComPtr 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((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 sample; + ComPtr 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 diff --git a/src/kiwano-audio/Transcoder.h b/src/kiwano-audio/Transcoder.h index 50afd1c0..7b69cdb8 100644 --- a/src/kiwano-audio/Transcoder.h +++ b/src/kiwano-audio/Transcoder.h @@ -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 diff --git a/src/kiwano-audio/kiwano-audio.h b/src/kiwano-audio/kiwano-audio.h index 041b7aa7..975d92e1 100644 --- a/src/kiwano-audio/kiwano-audio.h +++ b/src/kiwano-audio/kiwano-audio.h @@ -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 diff --git a/src/kiwano-audio/libraries.cpp b/src/kiwano-audio/libraries.cpp index 5239d216..2b060608 100644 --- a/src/kiwano-audio/libraries.cpp +++ b/src/kiwano-audio/libraries.cpp @@ -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 #include +#include 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("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("MFStartup"); - MFShutdown = mfplat.GetProcess("MFShutdown"); - MFCreateMediaType = mfplat.GetProcess("MFCreateMediaType"); - MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess("MFCreateWaveFormatExFromMFMediaType"); - MFCreateMFByteStreamOnStream = mfplat.GetProcess("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("MFCreateSourceReaderFromURL"); - MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess("MFCreateSourceReaderFromByteStream"); - } - else - { - KGE_ERROR(L"Load Mfreadwrite.dll failed"); - throw std::runtime_error("Load Mfreadwrite.dll failed"); - } - } - } - } + if (xaudio2.IsValid()) + { + XAudio2Create = xaudio2.GetProcess("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("MFStartup"); + MFShutdown = mfplat.GetProcess("MFShutdown"); + MFCreateMediaType = mfplat.GetProcess("MFCreateMediaType"); + MFCreateWaveFormatExFromMFMediaType = + mfplat.GetProcess("MFCreateWaveFormatExFromMFMediaType"); + MFCreateMFByteStreamOnStream = + mfplat.GetProcess("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("MFCreateSourceReaderFromURL"); + MFCreateSourceReaderFromByteStream = + mfreadwrite.GetProcess("MFCreateSourceReaderFromByteStream"); + } + else + { + KGE_ERROR(L"Load Mfreadwrite.dll failed"); + throw std::runtime_error("Load Mfreadwrite.dll failed"); + } +} +} // namespace dlls +} // namespace audio +} // namespace kiwano diff --git a/src/kiwano-audio/libraries.h b/src/kiwano-audio/libraries.h index 44d26bf7..35324db0 100644 --- a/src/kiwano-audio/libraries.h +++ b/src/kiwano-audio/libraries.h @@ -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 -#include #include #include #include +#include #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 diff --git a/src/kiwano-imgui/ImGuiLayer.cpp b/src/kiwano-imgui/ImGuiLayer.cpp index ae5ea8e7..94054b4d 100644 --- a/src/kiwano-imgui/ImGuiLayer.cpp +++ b/src/kiwano-imgui/ImGuiLayer.cpp @@ -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 diff --git a/src/kiwano-imgui/ImGuiLayer.h b/src/kiwano-imgui/ImGuiLayer.h index d62e5b0c..a377805e 100644 --- a/src/kiwano-imgui/ImGuiLayer.h +++ b/src/kiwano-imgui/ImGuiLayer.h @@ -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; +/// \~chinese +/// @brief ImGui管道 +using ImGuiPipeline = Function; - /** - * \~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 pipelines_; - }; - } -} +private: + Map pipelines_; +}; +} // namespace imgui +} // namespace kiwano diff --git a/src/kiwano-imgui/ImGuiModule.cpp b/src/kiwano-imgui/ImGuiModule.cpp index 0d5ff03f..fea5b179 100644 --- a/src/kiwano-imgui/ImGuiModule.cpp +++ b/src/kiwano-imgui/ImGuiModule.cpp @@ -1,209 +1,235 @@ // Copyright (C) 2019 Nomango +#include +#include #include #include #include -#include #include +#include #include -#include -#include 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()) - { - if (evt->IsType()) - { - MouseButton button = dynamic_cast(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()) - { - MouseButton button = dynamic_cast(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()) - { - float wheel = dynamic_cast(evt)->wheel; - io.MouseWheel += wheel; - } - } - else if (evt->IsType()) - { - if (evt->IsType()) - { - KeyCode key = dynamic_cast(evt)->code; - io.KeysDown[(int)key] = true; - } - else if (evt->IsType()) - { - KeyCode key = dynamic_cast(evt)->code; - io.KeysDown[(int)key] = false; - } - else if (evt->IsType()) - { - // You can also use ToAscii()+GetKeyboardState() to retrieve characters. - char ch = dynamic_cast(evt)->value; - io.AddInputCharacter(static_cast(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()) + { + if (evt->IsType()) + { + MouseButton button = dynamic_cast(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()) + { + MouseButton button = dynamic_cast(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()) + { + float wheel = dynamic_cast(evt)->wheel; + io.MouseWheel += wheel; + } + } + else if (evt->IsType()) + { + if (evt->IsType()) + { + KeyCode key = dynamic_cast(evt)->code; + io.KeysDown[(int)key] = true; + } + else if (evt->IsType()) + { + KeyCode key = dynamic_cast(evt)->code; + io.KeysDown[(int)key] = false; + } + else if (evt->IsType()) + { + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + char ch = dynamic_cast(evt)->value; + io.AddInputCharacter(static_cast(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 diff --git a/src/kiwano-imgui/ImGuiModule.h b/src/kiwano-imgui/ImGuiModule.h index d609edc8..33a2a2f5 100644 --- a/src/kiwano-imgui/ImGuiModule.h +++ b/src/kiwano-imgui/ImGuiModule.h @@ -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 - , public RenderComponent - , public UpdateComponent - , public EventComponent - { - friend Singleton; +namespace imgui +{ +/** + * \~chinese + * @brief ImGui模块 + */ +class ImGuiModule + : public Singleton + , public RenderComponent + , public UpdateComponent + , public EventComponent +{ + friend Singleton; - 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 diff --git a/src/kiwano-imgui/imgui_impl.h b/src/kiwano-imgui/imgui_impl.h index 72fb88cf..0402bcd5 100644 --- a/src/kiwano-imgui/imgui_impl.h +++ b/src/kiwano-imgui/imgui_impl.h @@ -8,25 +8,62 @@ #include -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 -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 diff --git a/src/kiwano-imgui/imgui_impl_dx10.cpp b/src/kiwano-imgui/imgui_impl_dx10.cpp index 8c0221be..78eedecf 100644 --- a/src/kiwano-imgui/imgui_impl_dx10.cpp +++ b/src/kiwano-imgui/imgui_impl_dx10.cpp @@ -3,40 +3,41 @@ #include // DirectX -#include -#include #include +#include #include +#include #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.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.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; } diff --git a/src/kiwano-imgui/imgui_impl_dx10.h b/src/kiwano-imgui/imgui_impl_dx10.h index 26fdb0c1..7fd26e53 100644 --- a/src/kiwano-imgui/imgui_impl_dx10.h +++ b/src/kiwano-imgui/imgui_impl_dx10.h @@ -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 diff --git a/src/kiwano-imgui/imgui_impl_dx11.cpp b/src/kiwano-imgui/imgui_impl_dx11.cpp index 470f914b..5fccb34d 100644 --- a/src/kiwano-imgui/imgui_impl_dx11.cpp +++ b/src/kiwano-imgui/imgui_impl_dx11.cpp @@ -3,40 +3,41 @@ #include // DirectX -#include #include #include +#include #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.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.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; } diff --git a/src/kiwano-imgui/imgui_impl_dx11.h b/src/kiwano-imgui/imgui_impl_dx11.h index 4964c00c..e15f79d1 100644 --- a/src/kiwano-imgui/imgui_impl_dx11.h +++ b/src/kiwano-imgui/imgui_impl_dx11.h @@ -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 diff --git a/src/kiwano-imgui/kiwano-imgui.h b/src/kiwano-imgui/kiwano-imgui.h index 453a1a0c..6f8a1ab2 100644 --- a/src/kiwano-imgui/kiwano-imgui.h +++ b/src/kiwano-imgui/kiwano-imgui.h @@ -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 diff --git a/src/kiwano-network/HttpClient.cpp b/src/kiwano-network/HttpClient.cpp index 65b0305d..b98a6f50 100644 --- a/src/kiwano-network/HttpClient.cpp +++ b/src/kiwano-network/HttpClient.cpp @@ -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 +#include <3rd-party/curl/curl.h> // CURL #include - +#include #include #include -#include - #include #include -#include <3rd-party/curl/curl.h> // CURL +#include 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> 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> 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 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 - 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 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 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 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 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> 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> 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 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 + 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 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 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 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 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 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 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 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 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 diff --git a/src/kiwano-network/HttpClient.h b/src/kiwano-network/HttpClient.h index 660380a3..c1a29b9b 100644 --- a/src/kiwano-network/HttpClient.h +++ b/src/kiwano-network/HttpClient.h @@ -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 #include #include #include -#include 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 - , public ComponentBase - { - friend Singleton; +/** + * \~chinese + * @brief HTTP客户端 + */ +class KGE_API HttpClient + : public Singleton + , public ComponentBase +{ + friend Singleton; - 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 request_queue_; + std::mutex request_mutex_; + Queue request_queue_; - std::mutex response_mutex_; - Queue response_queue_; + std::mutex response_mutex_; + Queue 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 diff --git a/src/kiwano-network/HttpRequest.cpp b/src/kiwano-network/HttpRequest.cpp index 610df352..6aacca61 100644 --- a/src/kiwano-network/HttpRequest.cpp +++ b/src/kiwano-network/HttpRequest.cpp @@ -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 diff --git a/src/kiwano-network/HttpRequest.h b/src/kiwano-network/HttpRequest.h index 69609be4..cc01a9cb 100644 --- a/src/kiwano-network/HttpRequest.h +++ b/src/kiwano-network/HttpRequest.h @@ -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; +/** + * \~chinese + * @brief HTTP请求 + */ +class KGE_API HttpRequest : public virtual ObjectBase +{ +public: + /// \~chinese + /// @brief 响应回调函数 + using ResponseCallback = Function; - /// \~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 const& headers); + /// \~chinese + /// @brief 设置HTTP头 + void SetHeaders(Map 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& GetHeaders(); + /// \~chinese + /// @brief 获取HTTP头 + Map& 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 headers_; - ResponseCallback response_cb_; - }; +private: + Type type_; + String url_; + String data_; + Map 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 const& headers) { headers_ = headers; } - - inline void HttpRequest::SetHeader(String const& field, String const& content) { headers_[field] = content; } - - inline Map& 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 const& headers) +{ + headers_ = headers; +} + +inline void HttpRequest::SetHeader(String const& field, String const& content) +{ + headers_[field] = content; +} + +inline Map& 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 diff --git a/src/kiwano-network/HttpResponse.hpp b/src/kiwano-network/HttpResponse.hpp index 42106e2e..0c91baa2 100644 --- a/src/kiwano-network/HttpResponse.hpp +++ b/src/kiwano-network/HttpResponse.hpp @@ -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 diff --git a/src/kiwano-network/kiwano-network.h b/src/kiwano-network/kiwano-network.h index e1078261..eb134a7a 100644 --- a/src/kiwano-network/kiwano-network.h +++ b/src/kiwano-network/kiwano-network.h @@ -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 #include #include -#include diff --git a/src/kiwano-physics/Body.cpp b/src/kiwano-physics/Body.cpp index cd4055c7..7698824b 100644 --- a/src/kiwano-physics/Body.cpp +++ b/src/kiwano-physics/Body.cpp @@ -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 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 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 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 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 diff --git a/src/kiwano-physics/Body.h b/src/kiwano-physics/Body.h index 6409bca4..25fd0c8e 100644 --- a/src/kiwano-physics/Body.h +++ b/src/kiwano-physics/Body.h @@ -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 -#include -#include #include +#include +#include +#include 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 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 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(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 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 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(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 diff --git a/src/kiwano-physics/Contact.cpp b/src/kiwano-physics/Contact.cpp index db133c94..4df8b5b5 100644 --- a/src/kiwano-physics/Contact.cpp +++ b/src/kiwano-physics/Contact.cpp @@ -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 #include +#include #include 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 diff --git a/src/kiwano-physics/Contact.h b/src/kiwano-physics/Contact.h index 68b43fd0..5e5a9a79 100644 --- a/src/kiwano-physics/Contact.h +++ b/src/kiwano-physics/Contact.h @@ -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 #include +#include 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 +{ + template + class IteratorImpl : public std::iterator + { + using herit = std::iterator; - /// \~chinese - /// @brief 物理接触列表 - class ContactList - : public List - { - template - class IteratorImpl - : public std::iterator - { - using herit = std::iterator; + public: + IteratorImpl(const _Ty& elem) + : elem_(elem) + { + } - public: - IteratorImpl(const _Ty& elem) - : elem_(elem) - { - } + inline typename herit::reference operator*() const + { + return const_cast(elem_); + } - inline typename herit::reference operator*() const - { - return const_cast(elem_); - } + inline typename herit::pointer operator->() const + { + return std::pointer_traits::pointer_to(**this); + } - inline typename herit::pointer operator->() const - { - return std::pointer_traits::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; + using const_iterator = IteratorImpl; - public: - using value_type = Contact; - using iterator = IteratorImpl; - using const_iterator = IteratorImpl; + 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 diff --git a/src/kiwano-physics/ContactEdge.cpp b/src/kiwano-physics/ContactEdge.cpp index f902edbc..9de13ff3 100644 --- a/src/kiwano-physics/ContactEdge.cpp +++ b/src/kiwano-physics/ContactEdge.cpp @@ -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 diff --git a/src/kiwano-physics/ContactEdge.h b/src/kiwano-physics/ContactEdge.h index 09f6eccc..bf500f90 100644 --- a/src/kiwano-physics/ContactEdge.h +++ b/src/kiwano-physics/ContactEdge.h @@ -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 + class IteratorImpl : public std::iterator + { + using herit = std::iterator; - /// \~chinese - /// @brief 物理接触边列表 - class ContactEdgeList - { - template - class IteratorImpl - : public std::iterator - { - using herit = std::iterator; + 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(elem_); + } - inline typename herit::reference operator*() const - { - return const_cast(elem_); - } + inline typename herit::pointer operator->() const + { + return std::pointer_traits::pointer_to(**this); + } - inline typename herit::pointer operator->() const - { - return std::pointer_traits::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; + using const_iterator = IteratorImpl; - public: - using value_type = ContactEdge; - using iterator = IteratorImpl; - using const_iterator = IteratorImpl; + 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(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(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 diff --git a/src/kiwano-physics/ContactEvent.cpp b/src/kiwano-physics/ContactEvent.cpp index 8e0be3b1..3a53912a 100644 --- a/src/kiwano-physics/ContactEvent.cpp +++ b/src/kiwano-physics/ContactEvent.cpp @@ -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 diff --git a/src/kiwano-physics/ContactEvent.h b/src/kiwano-physics/ContactEvent.h index 65679692..72fa1710 100644 --- a/src/kiwano-physics/ContactEvent.h +++ b/src/kiwano-physics/ContactEvent.h @@ -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 #include +#include 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 diff --git a/src/kiwano-physics/Fixture.cpp b/src/kiwano-physics/Fixture.cpp index 8eb2020b..7cf316fc 100644 --- a/src/kiwano-physics/Fixture.cpp +++ b/src/kiwano-physics/Fixture.cpp @@ -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 #include +#include #include 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(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(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 diff --git a/src/kiwano-physics/Fixture.h b/src/kiwano-physics/Fixture.h index df8885ba..e7f1d52b 100644 --- a/src/kiwano-physics/Fixture.h +++ b/src/kiwano-physics/Fixture.h @@ -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 #include +#include 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 - { - template - class IteratorImpl - : public std::iterator - { - using herit = std::iterator; +/// \~chinese +/// @brief 物理夹具列表 +class FixtureList : public List +{ + template + class IteratorImpl : public std::iterator + { + using herit = std::iterator; - public: - IteratorImpl(const _Ty& elem) - : elem_(elem) - { - } + public: + IteratorImpl(const _Ty& elem) + : elem_(elem) + { + } - inline typename herit::reference operator*() const - { - return const_cast(elem_); - } + inline typename herit::reference operator*() const + { + return const_cast(elem_); + } - inline typename herit::pointer operator->() const - { - return std::pointer_traits::pointer_to(**this); - } + inline typename herit::pointer operator->() const + { + return std::pointer_traits::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; - using const_iterator = IteratorImpl; +public: + using value_type = Fixture; + using iterator = IteratorImpl; + using const_iterator = IteratorImpl; - 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 diff --git a/src/kiwano-physics/Joint.cpp b/src/kiwano-physics/Joint.cpp index 2c9e7890..ed52c955 100644 --- a/src/kiwano-physics/Joint.cpp +++ b/src/kiwano-physics/Joint.cpp @@ -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,590 +23,593 @@ namespace kiwano { - namespace physics - { - // - // Joint - // - - Joint::Joint() - : joint_(nullptr) - , world_(nullptr) - , type_(Type::Unknown) - { - } - - Joint::~Joint() - { - Destroy(); - } - - bool Joint::InitJoint(World* world, b2JointDef* joint_def) - { - KGE_ASSERT(world); - - Destroy(); - - world_ = world; - if (world_) - { - world_->AddJoint(this); - - b2Joint* joint = world_->GetB2World()->CreateJoint(joint_def); - SetB2Joint(joint); - - return joint != nullptr; - } - return false; - } - - BodyPtr Joint::GetBodyA() const - { - KGE_ASSERT(joint_); - - b2Body* body = joint_->GetBodyA(); - return BodyPtr(static_cast(body->GetUserData())); - } - - BodyPtr Joint::GetBodyB() const - { - KGE_ASSERT(joint_); - - b2Body* body = joint_->GetBodyB(); - return BodyPtr(static_cast(body->GetUserData())); - } - - void Joint::SetB2Joint(b2Joint* joint) - { - joint_ = joint; - if (joint_) - { - type_ = Joint::Type(joint_->GetType()); - } - } - - void Joint::Destroy() - { - if (world_) - { - world_->RemoveJoint(this); - } - } - - // - // DistanceJoint - // - - DistanceJoint::DistanceJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool DistanceJoint::InitJoint(World* world, DistanceJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2DistanceJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor_a), world->Stage2World(param.anchor_b)); - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - void DistanceJoint::SetLength(float length) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetLength(GetWorld()->Stage2World(length)); - } - - float DistanceJoint::GetLength() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLength()); - } - - // - // FrictionJoint - // - - FrictionJoint::FrictionJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool FrictionJoint::InitJoint(World* world, FrictionJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2FrictionJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); - def.maxForce = param.max_force; - def.maxTorque = world->Stage2World(param.max_torque); - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - void FrictionJoint::SetMaxForce(float length) - { - KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxForce(length); - } - - float FrictionJoint::GetMaxForce() const - { - KGE_ASSERT(raw_joint_); - return raw_joint_->GetMaxForce(); - } - - void FrictionJoint::SetMaxTorque(float length) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); - } - - float FrictionJoint::GetMaxTorque() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); - } - - // - // GearJoint - // - - GearJoint::GearJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool GearJoint::InitJoint(World* world, GearJoint::Param const& param) - { - KGE_ASSERT(param.joint_a && param.joint_b); - - b2GearJointDef def; - def.joint1 = param.joint_a->GetB2Joint(); - def.joint2 = param.joint_b->GetB2Joint(); - def.ratio = param.ratio; - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - void GearJoint::SetRatio(float ratio) - { - KGE_ASSERT(raw_joint_); - raw_joint_->SetRatio(ratio); - } - - float GearJoint::GetRatio() const - { - KGE_ASSERT(raw_joint_); - return raw_joint_->GetRatio(); - } - - // - // MotorJoint - // - - MotorJoint::MotorJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool MotorJoint::InitJoint(World* world, MotorJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2MotorJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body()); - def.maxForce = param.max_force; - def.maxTorque = world->Stage2World(param.max_torque); - def.correctionFactor = param.correction_factor; - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - void MotorJoint::SetMaxForce(float length) - { - KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxForce(length); - } - - float MotorJoint::GetMaxForce() const - { - KGE_ASSERT(raw_joint_); - return raw_joint_->GetMaxForce(); - } - - void MotorJoint::SetMaxTorque(float length) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); - } - - float MotorJoint::GetMaxTorque() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); - } - - // - // PrismaticJoint - // - - PrismaticJoint::PrismaticJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool PrismaticJoint::InitJoint(World* world, PrismaticJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2PrismaticJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor), Stage2World(param.axis)); - def.enableLimit = param.enable_limit; - def.lowerTranslation = world->Stage2World(param.lower_translation); - def.upperTranslation = world->Stage2World(param.upper_translation); - def.enableMotor = param.enable_motor; - def.maxMotorForce = param.max_motor_force; - def.motorSpeed = world->Stage2World(param.motor_speed); - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - float PrismaticJoint::GetJointTranslation() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); - } - - float PrismaticJoint::GetJointSpeed() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointSpeed()); - } - - float PrismaticJoint::GetLowerLimit() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLowerLimit()); - } - - float PrismaticJoint::GetUpperLimit() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetUpperLimit()); - } - - void PrismaticJoint::SetLimits(float lower, float upper) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetLimits(GetWorld()->Stage2World(lower), GetWorld()->Stage2World(upper)); - } - - // - // PulleyJoint - // - - PulleyJoint::PulleyJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool PulleyJoint::InitJoint(World* world, PulleyJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2PulleyJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.ground_anchor_a), world->Stage2World(param.ground_anchor_b), - world->Stage2World(param.anchor_a), world->Stage2World(param.anchor_b), param.ratio); - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - Point PulleyJoint::GetGroundAnchorA() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorA()); - } - - Point PulleyJoint::GetGroundAnchorB() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorB()); - } - - float PulleyJoint::GetRatio() const - { - KGE_ASSERT(raw_joint_); - return raw_joint_->GetRatio(); - } - - float PulleyJoint::GetLengthA() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLengthA()); - } - - float PulleyJoint::GetLengthB() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLengthB()); - } - - float PulleyJoint::GetCurrentLengthA() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthA()); - } - - float PulleyJoint::GetCurrentLengthB() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthB()); - } - - // - // RevoluteJoint - // - - RevoluteJoint::RevoluteJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool RevoluteJoint::InitJoint(World* world, RevoluteJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2RevoluteJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); - def.enableLimit = param.enable_limit; - def.lowerAngle = math::Degree2Radian(param.lower_angle); - def.upperAngle = math::Degree2Radian(param.upper_angle); - def.enableMotor = param.enable_motor; - def.maxMotorTorque = world->Stage2World(param.max_motor_torque); - def.motorSpeed = math::Degree2Radian(param.motor_speed); - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - float RevoluteJoint::GetJointAngle() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return math::Radian2Degree(raw_joint_->GetJointAngle()); - } - - float RevoluteJoint::GetJointSpeed() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return math::Radian2Degree(raw_joint_->GetJointSpeed()); - } - - float RevoluteJoint::GetLowerLimit() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return math::Radian2Degree(raw_joint_->GetLowerLimit()); - } - - float RevoluteJoint::GetUpperLimit() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return math::Radian2Degree(raw_joint_->GetUpperLimit()); - } - - void RevoluteJoint::SetLimits(float lower, float upper) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetLimits(math::Degree2Radian(lower), math::Degree2Radian(upper)); - } - - void RevoluteJoint::SetMaxMotorTorque(float torque) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); - } - - float RevoluteJoint::GetMaxMotorTorque() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); - } - - // - // RopeJoint - // - - RopeJoint::RopeJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool RopeJoint::InitJoint(World* world, RopeJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2RopeJointDef def; - def.bodyA = param.body_a->GetB2Body(); - def.bodyB = param.body_b->GetB2Body(); - def.localAnchorA = world->Stage2World(param.local_anchor_a); - def.localAnchorB = world->Stage2World(param.local_anchor_b); - def.maxLength = world->Stage2World(param.max_length); - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - void RopeJoint::SetMaxLength(float length) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxLength(GetWorld()->Stage2World(length)); - } - - float RopeJoint::GetMaxLength() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxLength()); - } - - // - // WeldJoint - // - - WeldJoint::WeldJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool WeldJoint::InitJoint(World* world, WeldJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2WeldJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - - // - // WheelJoint - // - - WheelJoint::WheelJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool WheelJoint::InitJoint(World* world, WheelJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2WheelJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor), Stage2World(param.axis)); - def.enableMotor = param.enable_motor; - def.maxMotorTorque = world->Stage2World(param.max_motor_torque); - def.motorSpeed = world->Stage2World(param.motor_speed); - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - float WheelJoint::GetJointTranslation() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); - } - - float WheelJoint::GetJointLinearSpeed() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointLinearSpeed()); - } - - void WheelJoint::SetMaxMotorTorque(float torque) - { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); - } - - float WheelJoint::GetMaxMotorTorque() const - { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); - } - - // - // MouseJoint - // - - MouseJoint::MouseJoint() - : Joint() - , raw_joint_(nullptr) - { - } - - bool MouseJoint::InitJoint(World* world, MouseJoint::Param const& param) - { - KGE_ASSERT(param.body_a && param.body_b); - - b2MouseJointDef def; - def.bodyA = param.body_a->GetB2Body(); - def.bodyB = param.body_b->GetB2Body(); - def.target = world->Stage2World(param.target); - def.maxForce = param.max_force; - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; - - Joint::InitJoint(world, &def); - raw_joint_ = static_cast(GetB2Joint()); - return raw_joint_ != nullptr; - } - - void MouseJoint::SetMaxForce(float length) - { - KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxForce(length); - } - - float MouseJoint::GetMaxForce() const - { - KGE_ASSERT(raw_joint_); - return raw_joint_->GetMaxForce(); - } - +namespace physics +{ +// +// Joint +// + +Joint::Joint() + : joint_(nullptr) + , world_(nullptr) + , type_(Type::Unknown) +{ } + +Joint::~Joint() +{ + Destroy(); } + +bool Joint::InitJoint(World* world, b2JointDef* joint_def) +{ + KGE_ASSERT(world); + + Destroy(); + + world_ = world; + if (world_) + { + world_->AddJoint(this); + + b2Joint* joint = world_->GetB2World()->CreateJoint(joint_def); + SetB2Joint(joint); + + return joint != nullptr; + } + return false; +} + +BodyPtr Joint::GetBodyA() const +{ + KGE_ASSERT(joint_); + + b2Body* body = joint_->GetBodyA(); + return BodyPtr(static_cast(body->GetUserData())); +} + +BodyPtr Joint::GetBodyB() const +{ + KGE_ASSERT(joint_); + + b2Body* body = joint_->GetBodyB(); + return BodyPtr(static_cast(body->GetUserData())); +} + +void Joint::SetB2Joint(b2Joint* joint) +{ + joint_ = joint; + if (joint_) + { + type_ = Joint::Type(joint_->GetType()); + } +} + +void Joint::Destroy() +{ + if (world_) + { + world_->RemoveJoint(this); + } +} + +// +// DistanceJoint +// + +DistanceJoint::DistanceJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool DistanceJoint::InitJoint(World* world, DistanceJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2DistanceJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor_a), + world->Stage2World(param.anchor_b)); + def.frequencyHz = param.frequency_hz; + def.dampingRatio = param.damping_ratio; + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +void DistanceJoint::SetLength(float length) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetLength(GetWorld()->Stage2World(length)); +} + +float DistanceJoint::GetLength() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLength()); +} + +// +// FrictionJoint +// + +FrictionJoint::FrictionJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool FrictionJoint::InitJoint(World* world, FrictionJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2FrictionJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); + def.maxForce = param.max_force; + def.maxTorque = world->Stage2World(param.max_torque); + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +void FrictionJoint::SetMaxForce(float length) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxForce(length); +} + +float FrictionJoint::GetMaxForce() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetMaxForce(); +} + +void FrictionJoint::SetMaxTorque(float length) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); +} + +float FrictionJoint::GetMaxTorque() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); +} + +// +// GearJoint +// + +GearJoint::GearJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool GearJoint::InitJoint(World* world, GearJoint::Param const& param) +{ + KGE_ASSERT(param.joint_a && param.joint_b); + + b2GearJointDef def; + def.joint1 = param.joint_a->GetB2Joint(); + def.joint2 = param.joint_b->GetB2Joint(); + def.ratio = param.ratio; + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +void GearJoint::SetRatio(float ratio) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetRatio(ratio); +} + +float GearJoint::GetRatio() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetRatio(); +} + +// +// MotorJoint +// + +MotorJoint::MotorJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool MotorJoint::InitJoint(World* world, MotorJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2MotorJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body()); + def.maxForce = param.max_force; + def.maxTorque = world->Stage2World(param.max_torque); + def.correctionFactor = param.correction_factor; + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +void MotorJoint::SetMaxForce(float length) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxForce(length); +} + +float MotorJoint::GetMaxForce() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetMaxForce(); +} + +void MotorJoint::SetMaxTorque(float length) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); +} + +float MotorJoint::GetMaxTorque() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); +} + +// +// PrismaticJoint +// + +PrismaticJoint::PrismaticJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool PrismaticJoint::InitJoint(World* world, PrismaticJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2PrismaticJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor), + Stage2World(param.axis)); + def.enableLimit = param.enable_limit; + def.lowerTranslation = world->Stage2World(param.lower_translation); + def.upperTranslation = world->Stage2World(param.upper_translation); + def.enableMotor = param.enable_motor; + def.maxMotorForce = param.max_motor_force; + def.motorSpeed = world->Stage2World(param.motor_speed); + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +float PrismaticJoint::GetJointTranslation() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); +} + +float PrismaticJoint::GetJointSpeed() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointSpeed()); +} + +float PrismaticJoint::GetLowerLimit() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLowerLimit()); +} + +float PrismaticJoint::GetUpperLimit() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetUpperLimit()); +} + +void PrismaticJoint::SetLimits(float lower, float upper) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetLimits(GetWorld()->Stage2World(lower), GetWorld()->Stage2World(upper)); +} + +// +// PulleyJoint +// + +PulleyJoint::PulleyJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool PulleyJoint::InitJoint(World* world, PulleyJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2PulleyJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.ground_anchor_a), + world->Stage2World(param.ground_anchor_b), world->Stage2World(param.anchor_a), + world->Stage2World(param.anchor_b), param.ratio); + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +Point PulleyJoint::GetGroundAnchorA() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorA()); +} + +Point PulleyJoint::GetGroundAnchorB() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorB()); +} + +float PulleyJoint::GetRatio() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetRatio(); +} + +float PulleyJoint::GetLengthA() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLengthA()); +} + +float PulleyJoint::GetLengthB() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLengthB()); +} + +float PulleyJoint::GetCurrentLengthA() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthA()); +} + +float PulleyJoint::GetCurrentLengthB() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthB()); +} + +// +// RevoluteJoint +// + +RevoluteJoint::RevoluteJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool RevoluteJoint::InitJoint(World* world, RevoluteJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2RevoluteJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); + def.enableLimit = param.enable_limit; + def.lowerAngle = math::Degree2Radian(param.lower_angle); + def.upperAngle = math::Degree2Radian(param.upper_angle); + def.enableMotor = param.enable_motor; + def.maxMotorTorque = world->Stage2World(param.max_motor_torque); + def.motorSpeed = math::Degree2Radian(param.motor_speed); + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +float RevoluteJoint::GetJointAngle() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return math::Radian2Degree(raw_joint_->GetJointAngle()); +} + +float RevoluteJoint::GetJointSpeed() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return math::Radian2Degree(raw_joint_->GetJointSpeed()); +} + +float RevoluteJoint::GetLowerLimit() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return math::Radian2Degree(raw_joint_->GetLowerLimit()); +} + +float RevoluteJoint::GetUpperLimit() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return math::Radian2Degree(raw_joint_->GetUpperLimit()); +} + +void RevoluteJoint::SetLimits(float lower, float upper) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetLimits(math::Degree2Radian(lower), math::Degree2Radian(upper)); +} + +void RevoluteJoint::SetMaxMotorTorque(float torque) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); +} + +float RevoluteJoint::GetMaxMotorTorque() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); +} + +// +// RopeJoint +// + +RopeJoint::RopeJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool RopeJoint::InitJoint(World* world, RopeJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2RopeJointDef def; + def.bodyA = param.body_a->GetB2Body(); + def.bodyB = param.body_b->GetB2Body(); + def.localAnchorA = world->Stage2World(param.local_anchor_a); + def.localAnchorB = world->Stage2World(param.local_anchor_b); + def.maxLength = world->Stage2World(param.max_length); + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +void RopeJoint::SetMaxLength(float length) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxLength(GetWorld()->Stage2World(length)); +} + +float RopeJoint::GetMaxLength() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxLength()); +} + +// +// WeldJoint +// + +WeldJoint::WeldJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool WeldJoint::InitJoint(World* world, WeldJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2WeldJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); + def.frequencyHz = param.frequency_hz; + def.dampingRatio = param.damping_ratio; + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +// +// WheelJoint +// + +WheelJoint::WheelJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool WheelJoint::InitJoint(World* world, WheelJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2WheelJointDef def; + def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor), + Stage2World(param.axis)); + def.enableMotor = param.enable_motor; + def.maxMotorTorque = world->Stage2World(param.max_motor_torque); + def.motorSpeed = world->Stage2World(param.motor_speed); + def.frequencyHz = param.frequency_hz; + def.dampingRatio = param.damping_ratio; + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +float WheelJoint::GetJointTranslation() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); +} + +float WheelJoint::GetJointLinearSpeed() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointLinearSpeed()); +} + +void WheelJoint::SetMaxMotorTorque(float torque) +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); +} + +float WheelJoint::GetMaxMotorTorque() const +{ + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); +} + +// +// MouseJoint +// + +MouseJoint::MouseJoint() + : Joint() + , raw_joint_(nullptr) +{ +} + +bool MouseJoint::InitJoint(World* world, MouseJoint::Param const& param) +{ + KGE_ASSERT(param.body_a && param.body_b); + + b2MouseJointDef def; + def.bodyA = param.body_a->GetB2Body(); + def.bodyB = param.body_b->GetB2Body(); + def.target = world->Stage2World(param.target); + def.maxForce = param.max_force; + def.frequencyHz = param.frequency_hz; + def.dampingRatio = param.damping_ratio; + + Joint::InitJoint(world, &def); + raw_joint_ = static_cast(GetB2Joint()); + return raw_joint_ != nullptr; +} + +void MouseJoint::SetMaxForce(float length) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxForce(length); +} + +float MouseJoint::GetMaxForce() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetMaxForce(); +} + +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/Joint.h b/src/kiwano-physics/Joint.h index cae20a96..995fc876 100644 --- a/src/kiwano-physics/Joint.h +++ b/src/kiwano-physics/Joint.h @@ -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,1062 +19,1094 @@ // THE SOFTWARE. #pragma once -#include #include +#include namespace kiwano { - namespace physics - { - KGE_DECLARE_SMART_PTR(Joint); - KGE_DECLARE_SMART_PTR(DistanceJoint); - KGE_DECLARE_SMART_PTR(FrictionJoint); - KGE_DECLARE_SMART_PTR(GearJoint); - KGE_DECLARE_SMART_PTR(MotorJoint); - KGE_DECLARE_SMART_PTR(MouseJoint); - KGE_DECLARE_SMART_PTR(PrismaticJoint); - KGE_DECLARE_SMART_PTR(PulleyJoint); - KGE_DECLARE_SMART_PTR(RevoluteJoint); - KGE_DECLARE_SMART_PTR(RopeJoint); - KGE_DECLARE_SMART_PTR(WeldJoint); - KGE_DECLARE_SMART_PTR(WheelJoint); - - /** - * \addtogroup Physics - * @{ - */ - - /// \~chinese - /// @brief 关节 - class KGE_API Joint - : public virtual ObjectBase - { - public: - /// \~chinese - /// @brief 关节类型 - enum class Type - { - Unknown = 0, ///< 未知 - Revolute, ///< 旋转关节 - Prismatic, ///< 平移关节 - Distance, ///< 固定距离关节 - Pulley, ///< 滑轮关节 - Mouse, ///< 鼠标关节 - Gear, ///< 齿轮关节 - Wheel, ///< 轮关节 - Weld, ///< 焊接关节 - Friction, ///< 摩擦关节 - Rope, ///< 绳关节 - Motor ///< 马达关节 - }; - - /// \~chinese - /// @brief 关节基础参数 - struct ParamBase - { - Body* body_a; ///< 关节连接的物体A - Body* body_b; ///< 关节连接的物体B - - ParamBase(Body* body_a, Body* body_b) - : body_a(body_a), body_b(body_b) - { - } - - ParamBase(BodyPtr body_a, BodyPtr body_b) - : body_a(body_a.get()), body_b(body_b.get()) - { - } - }; - - Joint(); - - virtual ~Joint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, b2JointDef* joint_def); - - /// \~chinese - /// @brief 获取关节连接的物体A - BodyPtr GetBodyA() const; - - /// \~chinese - /// @brief 获取关节连接的物体B - BodyPtr GetBodyB() const; - - /// \~chinese - /// @brief 获取物理世界 - World* GetWorld() const; - - /// \~chinese - /// @brief 销毁关节 - void Destroy(); - - b2Joint* GetB2Joint() const; - void SetB2Joint(b2Joint* joint); - - private: - b2Joint* joint_; - World* world_; - Type type_; - }; - - - /// \~chinese - /// @brief 固定距离关节 - class KGE_API DistanceJoint - : public Joint - { - public: - /// \~chinese - /// @brief 固定距离关节参数 - struct Param : public Joint::ParamBase - { - Point anchor_a; ///< 关节在物体A上的连接点 - Point anchor_b; ///< 关节在物体B上的连接点 - float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 - float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 - - Param( - Body* body_a, - Body* body_b, - Point const& anchor_a, - Point const& anchor_b, - float frequency_hz = 0.f, - float damping_ratio = 0.f - ) - : ParamBase(body_a, body_b) - , anchor_a(anchor_a) - , anchor_b(anchor_b) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor_a, - Point const& anchor_b, - float frequency_hz = 0.f, - float damping_ratio = 0.f - ) - : Param(body_a.get(), body_b.get(), anchor_a, anchor_b, frequency_hz, damping_ratio) - {} - }; - - DistanceJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 设置关节长度 - void SetLength(float length); - - /// \~chinese - /// @brief 获取关节长度 - float GetLength() const; - - /// \~chinese - /// @brief 设置弹簧响应速度 [赫兹] - void SetFrequency(float hz); - - /// \~chinese - /// @brief 获取弹簧响应速度 [赫兹] - float GetFrequency() const; - - /// \~chinese - /// @brief 设置阻尼率 - void SetDampingRatio(float ratio); - - /// \~chinese - /// @brief 获取阻尼率 - float GetDampingRatio() const; - - private: - b2DistanceJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 摩擦关节 - class KGE_API FrictionJoint - : public Joint - { - public: - struct Param : public Joint::ParamBase - { - Point anchor; ///< 摩擦作用点 - float max_force; ///< 最大摩擦力 - float max_torque; ///< 最大扭力 - - Param( - Body* body_a, - Body* body_b, - Point const& anchor, - float max_force = 0.f, - float max_torque = 0.f - ) - : ParamBase(body_a, body_b) - , anchor(anchor) - , max_force(max_force) - , max_torque(max_torque) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor, - float max_force = 0.f, - float max_torque = 0.f - ) - : Param(body_a.get(), body_b.get(), anchor, max_force, max_torque) - {} - }; - - FrictionJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 设置最大摩擦力 - void SetMaxForce(float force); - - /// \~chinese - /// @brief 获取最大摩擦力 - float GetMaxForce() const; - - /// \~chinese - /// @brief 设置最大转矩 - void SetMaxTorque(float torque); - - /// \~chinese - /// @brief 获取最大转矩 - float GetMaxTorque() const; - - private: - b2FrictionJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 齿轮关节 - class KGE_API GearJoint - : public Joint - { - public: - /// \~chinese - /// @brief 齿轮关节参数 - struct Param : public Joint::ParamBase - { - Joint* joint_a; ///< 关节A(旋转关节/平移关节) - Joint* joint_b; ///< 关节B(旋转关节/平移关节) - float ratio; ///< 齿轮传动比 - - Param( - Joint* joint_a, - Joint* joint_b, - float ratio = 1.f - ) - : ParamBase(nullptr, nullptr) - , joint_a(joint_a) - , joint_b(joint_b) - , ratio(ratio) - {} - - Param( - JointPtr joint_a, - JointPtr joint_b, - float ratio = 1.f - ) - : Param(joint_a.get(), joint_b.get(), ratio) - {} - }; - - GearJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 设定齿轮传动比 - void SetRatio(float ratio); - - /// \~chinese - /// @brief 获取齿轮传动比 - float GetRatio() const; - - private: - b2GearJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 马达关节 - class KGE_API MotorJoint - : public Joint - { - public: - /// \~chinese - /// @brief 马达关节参数 - struct Param : public Joint::ParamBase - { - float max_force; ///< 最大摩擦力 - float max_torque; ///< 最大转矩 - float correction_factor; ///< 位置矫正因子(范围 0-1) - - Param( - Body* body_a, - Body* body_b, - float max_force = 1.f, - float max_torque = 100.f, - float correction_factor = 0.3f - ) - : ParamBase(body_a, body_b) - , max_force(max_force) - , max_torque(max_torque) - , correction_factor(correction_factor) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - float max_force = 0.f, - float max_torque = 0.f, - float correction_factor = 0.3f - ) - : Param(body_a.get(), body_b.get(), max_force, max_torque, correction_factor) - {} - }; - - MotorJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 设置最大摩擦力 - void SetMaxForce(float force); - - /// \~chinese - /// @brief 获取最大摩擦力 - float GetMaxForce() const; - - /// \~chinese - /// @brief 设置最大转矩 - void SetMaxTorque(float torque); - - /// \~chinese - /// @brief 获取最大转矩 - float GetMaxTorque() const; - - private: - b2MotorJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 平移关节 - class KGE_API PrismaticJoint - : public Joint - { - public: - /// \~chinese - /// @brief 平移关节参数 - struct Param : public Joint::ParamBase - { - Point anchor; ///< 关节位置 - Vec2 axis; ///< 物体A滑动的方向 - bool enable_limit; ///< 是否启用限制 - float lower_translation; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 - float upper_translation; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 - bool enable_motor; ///< 是否启用马达 - float max_motor_force; ///< 最大马达力 [N] - float motor_speed; ///< 马达转速 [degree/s] - - Param( - Body* body_a, - Body* body_b, - Point const& anchor, - Vec2 const& axis, - bool enable_limit = false, - float lower_translation = 0.0f, - float upper_translation = 0.0f, - bool enable_motor = false, - float max_motor_force = 0.0f, - float motor_speed = 0.0f - ) - : ParamBase(body_a, body_b) - , anchor(anchor) - , axis(axis) - , enable_limit(enable_limit) - , lower_translation(lower_translation) - , upper_translation(upper_translation) - , enable_motor(enable_motor) - , max_motor_force(max_motor_force) - , motor_speed(motor_speed) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor, - Vec2 const& axis, - bool enable_limit = false, - float lower_translation = 0.0f, - float upper_translation = 0.0f, - bool enable_motor = false, - float max_motor_force = 0.0f, - float motor_speed = 0.0f - ) - : Param(body_a.get(), body_b.get(), anchor, axis, enable_limit, lower_translation, upper_translation, enable_motor, max_motor_force, motor_speed) - {} - }; - - PrismaticJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 获取参考角 - float GetReferenceAngle() const; - - /// \~chinese - /// @brief 获取关节转换 - float GetJointTranslation() const; - - /// \~chinese - /// @brief 获取关节速度 - float GetJointSpeed() const; - - /// \~chinese - /// @brief 是否启用关节限制 - bool IsLimitEnabled() const; - - /// \~chinese - /// @brief 设置是否启用关节限制 - void EnableLimit(bool flag); - - /// \~chinese - /// @brief 获取平移最小限制 - float GetLowerLimit() const; - - /// \~chinese - /// @brief 获取平移最大限制 - float GetUpperLimit() const; - - /// \~chinese - /// @brief 设置关节限制 - void SetLimits(float lower, float upper); - - /// \~chinese - /// @brief 是否启用马达 - bool IsMotorEnabled() const; - - /// \~chinese - /// @brief 设置是否启用马达 - void EnableMotor(bool flag); - - /// \~chinese - /// @brief 设置马达转速 [degree/s] - void SetMotorSpeed(float speed); - - /// \~chinese - /// @brief 获取马达转速 [degree/s] - float GetMotorSpeed() const; - - /// \~chinese - /// @brief 设置最大马达力 [N] - void SetMaxMotorForce(float force); - - /// \~chinese - /// @brief 获取最大马达力 [N] - float GetMaxMotorForce() const; - - private: - b2PrismaticJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 滑轮关节 - class KGE_API PulleyJoint - : public Joint - { - public: - /// \~chinese - /// @brief 滑轮关节参数 - struct Param : public Joint::ParamBase - { - Point anchor_a; ///< 关节在物体A上的作用点 - Point anchor_b; ///< 关节在物体B上的作用点 - Point ground_anchor_a; ///< 物体A对应的滑轮的位置 - Point ground_anchor_b; ///< 物体B对应的滑轮的位置 - float ratio; ///< 滑轮比,关节传动时,滑轮上升和下降的两头的位移比例 - - Param( - Body* body_a, - Body* body_b, - Point const& anchor_a, - Point const& anchor_b, - Point const& ground_anchor_a, - Point const& ground_anchor_b, - float ratio = 1.0f - ) - : ParamBase(body_a, body_b) - , anchor_a(anchor_a) - , anchor_b(anchor_b) - , ground_anchor_a(ground_anchor_a) - , ground_anchor_b(ground_anchor_b) - , ratio(ratio) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor_a, - Point const& anchor_b, - Point const& ground_anchor_a, - Point const& ground_anchor_b, - float ratio = 1.0f - ) - : Param(body_a.get(), body_b.get(), anchor_a, anchor_b, ground_anchor_a, ground_anchor_b, ratio) - {} - }; - - PulleyJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 物体A对应的滑轮的位置 - Point GetGroundAnchorA() const; - - /// \~chinese - /// @brief 物体B对应的滑轮的位置 - Point GetGroundAnchorB() const; - - /// \~chinese - /// @brief 获取滑轮传动比 - float GetRatio() const; - - /// \~chinese - /// @brief 获取物体A与滑轮的距离 - float GetLengthA() const; - - /// \~chinese - /// @brief 获取物体B与滑轮的距离 - float GetLengthB() const; - - /// \~chinese - /// @brief 获取物体A与滑轮的当前距离 - float GetCurrentLengthA() const; - - /// \~chinese - /// @brief 获取物体B与滑轮的当前距离 - float GetCurrentLengthB() const; - - private: - b2PulleyJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 旋转关节 - class KGE_API RevoluteJoint - : public Joint - { - public: - /// \~chinese - /// @brief 旋转关节参数 - struct Param : public Joint::ParamBase - { - Point anchor; ///< 关节位置 - bool enable_limit; ///< 是否启用限制 - float lower_angle; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 - float upper_angle; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 - bool enable_motor; ///< 是否启用马达 - float max_motor_torque; ///< 最大马达力 [N] - float motor_speed; ///< 马达转速 [degree/s] - - Param( - Body* body_a, - Body* body_b, - Point const& anchor, - bool enable_limit = false, - float lower_angle = 0.0f, - float upper_angle = 0.0f, - bool enable_motor = false, - float max_motor_torque = 0.0f, - float motor_speed = 0.0f - ) - : ParamBase(body_a, body_b) - , anchor(anchor) - , enable_limit(enable_limit) - , lower_angle(lower_angle) - , upper_angle(upper_angle) - , enable_motor(enable_motor) - , max_motor_torque(max_motor_torque) - , motor_speed(motor_speed) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor, - bool enable_limit = false, - float lower_angle = 0.0f, - float upper_angle = 0.0f, - bool enable_motor = false, - float max_motor_torque = 0.0f, - float motor_speed = 0.0f - ) - : Param(body_a.get(), body_b.get(), anchor, enable_limit, lower_angle, upper_angle, enable_motor, max_motor_torque, motor_speed) - {} - }; - - RevoluteJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 获取参考角 - float GetReferenceAngle() const; - - /// \~chinese - /// @brief 获取关节角度 - float GetJointAngle() const; - - /// \~chinese - /// @brief 获取关节速度 - float GetJointSpeed() const; - - /// \~chinese - /// @brief 是否启用关节限制 - bool IsLimitEnabled() const; - - /// \~chinese - /// @brief 设置是否启用关节限制 - void EnableLimit(bool flag); - - /// \~chinese - /// @brief 获取平移最小限制 - float GetLowerLimit() const; - - /// \~chinese - /// @brief 获取平移最大限制 - float GetUpperLimit() const; - - /// \~chinese - /// @brief 设置关节限制 - void SetLimits(float lower, float upper); - - /// \~chinese - /// @brief 是否启用马达 - bool IsMotorEnabled() const; - - /// \~chinese - /// @brief 设置是否启用马达 - void EnableMotor(bool flag); - - /// \~chinese - /// @brief 设置马达转速 [degree/s] - void SetMotorSpeed(float speed); - - /// \~chinese - /// @brief 获取马达转速 [degree/s] - float GetMotorSpeed() const; - - /// \~chinese - /// @brief 设置最大马达转矩 [N/m] - void SetMaxMotorTorque(float torque); - - /// \~chinese - /// @brief 获取最大马达转矩 [N/m] - float GetMaxMotorTorque() const; - - private: - b2RevoluteJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 绳关节 - class KGE_API RopeJoint - : public Joint - { - public: - /// \~chinese - /// @brief 绳关节参数 - struct Param : public Joint::ParamBase - { - Point local_anchor_a; ///< 关节在物体A上的连接点 - Point local_anchor_b; ///< 关节在物体B上的连接点 - float max_length; ///< 绳索最大长度 - - Param( - Body* body_a, - Body* body_b, - Point const& local_anchor_a, - Point const& local_anchor_b, - float max_length = 0.f - ) - : ParamBase(body_a, body_b) - , local_anchor_a(local_anchor_a) - , local_anchor_b(local_anchor_b) - , max_length(max_length) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& local_anchor_a, - Point const& local_anchor_b, - float max_length = 0.f - ) - : Param(body_a.get(), body_b.get(), local_anchor_a, local_anchor_b, max_length) - {} - }; - - RopeJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 设置关节最大长度 - void SetMaxLength(float length); - - /// \~chinese - /// @brief 获取关节最大长度 - float GetMaxLength() const; - - private: - b2RopeJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 焊接关节 - class KGE_API WeldJoint - : public Joint - { - public: - /// \~chinese - /// @brief 焊接关节参数 - struct Param : public Joint::ParamBase - { - Point anchor; ///< 焊接位置 - float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 - float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 - - Param( - Body* body_a, - Body* body_b, - Point const& anchor, - float frequency_hz = 0.f, - float damping_ratio = 0.f - ) - : ParamBase(body_a, body_b) - , anchor(anchor) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor, - float frequency_hz = 0.f, - float damping_ratio = 0.f - ) - : Param(body_a.get(), body_b.get(), anchor, frequency_hz, damping_ratio) - {} - }; - - WeldJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 获取物体B相对于物体A的角度 - float GetReferenceAngle() const; - - /// \~chinese - /// @brief 设置弹簧响应速度 [赫兹] - void SetFrequency(float hz); - - /// \~chinese - /// @brief 获取弹簧响应速度 [赫兹] - float GetFrequency() const; - - /// \~chinese - /// @brief 设置阻尼率 - void SetDampingRatio(float ratio); - - /// \~chinese - /// @brief 获取阻尼率 - float GetDampingRatio() const; - - private: - b2WeldJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 轮关节 - class KGE_API WheelJoint - : public Joint - { - public: - /// \~chinese - /// @brief 轮关节参数 - struct Param : public Joint::ParamBase - { - Point anchor; ///< 轮关节位置 - Vec2 axis; ///< 物体A滑动方向 - bool enable_motor; ///< 是否启用马达 - float max_motor_torque; ///< 最大马达力 [N] - float motor_speed; ///< 马达转速 [degree/s] - float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 - float damping_ratio; ///< 弹簧阻尼率,值越大关节运动阻尼越大 - - Param( - Body* body_a, - Body* body_b, - Point const& anchor, - Vec2 const& axis, - float frequency_hz = 2.0f, - float damping_ratio = 0.7f, - bool enable_motor = false, - float max_motor_torque = 0.0f, - float motor_speed = 0.0f - ) - : ParamBase(body_a, body_b) - , anchor(anchor) - , axis(axis) - , enable_motor(enable_motor) - , max_motor_torque(max_motor_torque) - , motor_speed(motor_speed) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) - {} - - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& anchor, - Vec2 const& axis, - float frequency_hz = 2.0f, - float damping_ratio = 0.7f, - bool enable_motor = false, - float max_motor_torque = 0.0f, - float motor_speed = 0.0f - ) - : Param(body_a.get(), body_b.get(), anchor, axis, frequency_hz, damping_ratio, enable_motor, max_motor_torque, motor_speed) - {} - }; - - WheelJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 获取关节当前的平移距离 - float GetJointTranslation() const; - - /// \~chinese - /// @brief 获取关节当前的线性速度 - float GetJointLinearSpeed() const; - - /// \~chinese - /// @brief 获取关节当前的角度 - float GetJointAngle() const; - - /// \~chinese - /// @brief 获取关节当前的旋转速度 - float GetJointAngularSpeed() const; - - /// \~chinese - /// @brief 是否启用马达 - bool IsMotorEnabled() const; - - /// \~chinese - /// @brief 设置是否启用马达 - void EnableMotor(bool flag); - - /// \~chinese - /// @brief 设置马达转速 [degree/s] - void SetMotorSpeed(float speed); - - /// \~chinese - /// @brief 获取马达转速 [degree/s] - float GetMotorSpeed() const; - - /// \~chinese - /// @brief 设置最大马达转矩 [N/m] - void SetMaxMotorTorque(float torque); - - /// \~chinese - /// @brief 获取最大马达转矩 [N/m] - float GetMaxMotorTorque() const; - - /// \~chinese - /// @brief 设置弹簧响应速度 - void SetSpringFrequencyHz(float hz); - - /// \~chinese - /// @brief 获取弹簧响应速度 - float GetSpringFrequencyHz() const; - - /// \~chinese - /// @brief 设置弹簧阻尼率 - void SetSpringDampingRatio(float ratio); - - /// \~chinese - /// @brief 获取弹簧阻尼率 - float GetSpringDampingRatio() const; - - private: - b2WheelJoint* raw_joint_; - }; - - - /// \~chinese - /// @brief 鼠标关节 - /// @details 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置 - class KGE_API MouseJoint - : public Joint - { - public: - /// \~chinese - /// @brief 鼠标关节参数 - struct Param : public Joint::ParamBase - { - Point target; ///< 关节作用目标位置 - float max_force; ///< 作用在物体A上的最大力 - float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 - float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 - - Param( - Body* body_a, - Body* body_b, - Point const& target, - float max_force, - float frequency_hz = 5.0f, - float damping_ratio = 0.7f - ) - : ParamBase(body_a, body_b) - , target(target) - , max_force(max_force) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) - {} - - Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f, float damping_ratio = 0.7f) - : Param(body_a.get(), body_b.get(), target, max_force, frequency_hz, damping_ratio) - {} - }; - - MouseJoint(); - - /// \~chinese - /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); - - /// \~chinese - /// @brief 设定最大摩擦力 [N] - void SetMaxForce(float force); - - /// \~chinese - /// @brief 获取最大摩擦力 [N] - float GetMaxForce() const; - - /// \~chinese - /// @brief 设置响应速度 [hz] - void SetFrequency(float hz); - - /// \~chinese - /// @brief 获取响应速度 [hz] - float GetFrequency() const; - - /// \~chinese - /// @brief 设置阻尼率 - void SetDampingRatio(float ratio); - - /// \~chinese - /// @brief 获取阻尼率 - float GetDampingRatio() const; - - private: - b2MouseJoint* raw_joint_; - }; - - /** @} */ - - - inline b2Joint* Joint::GetB2Joint() const { return joint_; } - inline World* Joint::GetWorld() const { return world_; } - - inline void DistanceJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } - inline float DistanceJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } - inline void DistanceJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } - inline float DistanceJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } - - inline float PrismaticJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } - inline bool PrismaticJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } - inline void PrismaticJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } - inline bool PrismaticJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } - inline void PrismaticJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } - inline void PrismaticJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } - inline float PrismaticJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } - inline void PrismaticJoint::SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); } - inline float PrismaticJoint::GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); } - - inline float RevoluteJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } - inline bool RevoluteJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } - inline void RevoluteJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } - inline bool RevoluteJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } - inline void RevoluteJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } - inline void RevoluteJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } - inline float RevoluteJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } - - inline float WeldJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } - inline void WeldJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } - inline float WeldJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } - inline void WeldJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } - inline float WeldJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } - - inline float WheelJoint::GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); } - inline float WheelJoint::GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); } - inline bool WheelJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } - inline void WheelJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } - inline void WheelJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } - inline float WheelJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } - inline void WheelJoint::SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); } - inline float WheelJoint::GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); } - inline void WheelJoint::SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); } - inline float WheelJoint::GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); } - - inline void MouseJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } - inline float MouseJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } - inline void MouseJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } - inline float MouseJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } - } +namespace physics +{ +KGE_DECLARE_SMART_PTR(Joint); +KGE_DECLARE_SMART_PTR(DistanceJoint); +KGE_DECLARE_SMART_PTR(FrictionJoint); +KGE_DECLARE_SMART_PTR(GearJoint); +KGE_DECLARE_SMART_PTR(MotorJoint); +KGE_DECLARE_SMART_PTR(MouseJoint); +KGE_DECLARE_SMART_PTR(PrismaticJoint); +KGE_DECLARE_SMART_PTR(PulleyJoint); +KGE_DECLARE_SMART_PTR(RevoluteJoint); +KGE_DECLARE_SMART_PTR(RopeJoint); +KGE_DECLARE_SMART_PTR(WeldJoint); +KGE_DECLARE_SMART_PTR(WheelJoint); + +/** + * \addtogroup Physics + * @{ + */ + +/// \~chinese +/// @brief 关节 +class KGE_API Joint : public virtual ObjectBase +{ +public: + /// \~chinese + /// @brief 关节类型 + enum class Type + { + Unknown = 0, ///< 未知 + Revolute, ///< 旋转关节 + Prismatic, ///< 平移关节 + Distance, ///< 固定距离关节 + Pulley, ///< 滑轮关节 + Mouse, ///< 鼠标关节 + Gear, ///< 齿轮关节 + Wheel, ///< 轮关节 + Weld, ///< 焊接关节 + Friction, ///< 摩擦关节 + Rope, ///< 绳关节 + Motor ///< 马达关节 + }; + + /// \~chinese + /// @brief 关节基础参数 + struct ParamBase + { + Body* body_a; ///< 关节连接的物体A + Body* body_b; ///< 关节连接的物体B + + ParamBase(Body* body_a, Body* body_b) + : body_a(body_a) + , body_b(body_b) + { + } + + ParamBase(BodyPtr body_a, BodyPtr body_b) + : body_a(body_a.get()) + , body_b(body_b.get()) + { + } + }; + + Joint(); + + virtual ~Joint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, b2JointDef* joint_def); + + /// \~chinese + /// @brief 获取关节连接的物体A + BodyPtr GetBodyA() const; + + /// \~chinese + /// @brief 获取关节连接的物体B + BodyPtr GetBodyB() const; + + /// \~chinese + /// @brief 获取物理世界 + World* GetWorld() const; + + /// \~chinese + /// @brief 销毁关节 + void Destroy(); + + b2Joint* GetB2Joint() const; + void SetB2Joint(b2Joint* joint); + +private: + b2Joint* joint_; + World* world_; + Type type_; +}; + +/// \~chinese +/// @brief 固定距离关节 +class KGE_API DistanceJoint : public Joint +{ +public: + /// \~chinese + /// @brief 固定距离关节参数 + struct Param : public Joint::ParamBase + { + Point anchor_a; ///< 关节在物体A上的连接点 + Point anchor_b; ///< 关节在物体B上的连接点 + float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 + float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 + + Param(Body* body_a, Body* body_b, Point const& anchor_a, Point const& anchor_b, float frequency_hz = 0.f, + float damping_ratio = 0.f) + : ParamBase(body_a, body_b) + , anchor_a(anchor_a) + , anchor_b(anchor_b) + , frequency_hz(frequency_hz) + , damping_ratio(damping_ratio) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor_a, Point const& anchor_b, float frequency_hz = 0.f, + float damping_ratio = 0.f) + : Param(body_a.get(), body_b.get(), anchor_a, anchor_b, frequency_hz, damping_ratio) + { + } + }; + + DistanceJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 设置关节长度 + void SetLength(float length); + + /// \~chinese + /// @brief 获取关节长度 + float GetLength() const; + + /// \~chinese + /// @brief 设置弹簧响应速度 [赫兹] + void SetFrequency(float hz); + + /// \~chinese + /// @brief 获取弹簧响应速度 [赫兹] + float GetFrequency() const; + + /// \~chinese + /// @brief 设置阻尼率 + void SetDampingRatio(float ratio); + + /// \~chinese + /// @brief 获取阻尼率 + float GetDampingRatio() const; + +private: + b2DistanceJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 摩擦关节 +class KGE_API FrictionJoint : public Joint +{ +public: + struct Param : public Joint::ParamBase + { + Point anchor; ///< 摩擦作用点 + float max_force; ///< 最大摩擦力 + float max_torque; ///< 最大扭力 + + Param(Body* body_a, Body* body_b, Point const& anchor, float max_force = 0.f, float max_torque = 0.f) + : ParamBase(body_a, body_b) + , anchor(anchor) + , max_force(max_force) + , max_torque(max_torque) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, float max_force = 0.f, float max_torque = 0.f) + : Param(body_a.get(), body_b.get(), anchor, max_force, max_torque) + { + } + }; + + FrictionJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 设置最大摩擦力 + void SetMaxForce(float force); + + /// \~chinese + /// @brief 获取最大摩擦力 + float GetMaxForce() const; + + /// \~chinese + /// @brief 设置最大转矩 + void SetMaxTorque(float torque); + + /// \~chinese + /// @brief 获取最大转矩 + float GetMaxTorque() const; + +private: + b2FrictionJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 齿轮关节 +class KGE_API GearJoint : public Joint +{ +public: + /// \~chinese + /// @brief 齿轮关节参数 + struct Param : public Joint::ParamBase + { + Joint* joint_a; ///< 关节A(旋转关节/平移关节) + Joint* joint_b; ///< 关节B(旋转关节/平移关节) + float ratio; ///< 齿轮传动比 + + Param(Joint* joint_a, Joint* joint_b, float ratio = 1.f) + : ParamBase(nullptr, nullptr) + , joint_a(joint_a) + , joint_b(joint_b) + , ratio(ratio) + { + } + + Param(JointPtr joint_a, JointPtr joint_b, float ratio = 1.f) + : Param(joint_a.get(), joint_b.get(), ratio) + { + } + }; + + GearJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 设定齿轮传动比 + void SetRatio(float ratio); + + /// \~chinese + /// @brief 获取齿轮传动比 + float GetRatio() const; + +private: + b2GearJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 马达关节 +class KGE_API MotorJoint : public Joint +{ +public: + /// \~chinese + /// @brief 马达关节参数 + struct Param : public Joint::ParamBase + { + float max_force; ///< 最大摩擦力 + float max_torque; ///< 最大转矩 + float correction_factor; ///< 位置矫正因子(范围 0-1) + + Param(Body* body_a, Body* body_b, float max_force = 1.f, float max_torque = 100.f, + float correction_factor = 0.3f) + : ParamBase(body_a, body_b) + , max_force(max_force) + , max_torque(max_torque) + , correction_factor(correction_factor) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, float max_force = 0.f, float max_torque = 0.f, + float correction_factor = 0.3f) + : Param(body_a.get(), body_b.get(), max_force, max_torque, correction_factor) + { + } + }; + + MotorJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 设置最大摩擦力 + void SetMaxForce(float force); + + /// \~chinese + /// @brief 获取最大摩擦力 + float GetMaxForce() const; + + /// \~chinese + /// @brief 设置最大转矩 + void SetMaxTorque(float torque); + + /// \~chinese + /// @brief 获取最大转矩 + float GetMaxTorque() const; + +private: + b2MotorJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 平移关节 +class KGE_API PrismaticJoint : public Joint +{ +public: + /// \~chinese + /// @brief 平移关节参数 + struct Param : public Joint::ParamBase + { + Point anchor; ///< 关节位置 + Vec2 axis; ///< 物体A滑动的方向 + bool enable_limit; ///< 是否启用限制 + float lower_translation; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 + float upper_translation; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 + bool enable_motor; ///< 是否启用马达 + float max_motor_force; ///< 最大马达力 [N] + float motor_speed; ///< 马达转速 [degree/s] + + Param(Body* body_a, Body* body_b, Point const& anchor, Vec2 const& axis, bool enable_limit = false, + float lower_translation = 0.0f, float upper_translation = 0.0f, bool enable_motor = false, + float max_motor_force = 0.0f, float motor_speed = 0.0f) + : ParamBase(body_a, body_b) + , anchor(anchor) + , axis(axis) + , enable_limit(enable_limit) + , lower_translation(lower_translation) + , upper_translation(upper_translation) + , enable_motor(enable_motor) + , max_motor_force(max_motor_force) + , motor_speed(motor_speed) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, Vec2 const& axis, bool enable_limit = false, + float lower_translation = 0.0f, float upper_translation = 0.0f, bool enable_motor = false, + float max_motor_force = 0.0f, float motor_speed = 0.0f) + : Param(body_a.get(), body_b.get(), anchor, axis, enable_limit, lower_translation, upper_translation, + enable_motor, max_motor_force, motor_speed) + { + } + }; + + PrismaticJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 获取参考角 + float GetReferenceAngle() const; + + /// \~chinese + /// @brief 获取关节转换 + float GetJointTranslation() const; + + /// \~chinese + /// @brief 获取关节速度 + float GetJointSpeed() const; + + /// \~chinese + /// @brief 是否启用关节限制 + bool IsLimitEnabled() const; + + /// \~chinese + /// @brief 设置是否启用关节限制 + void EnableLimit(bool flag); + + /// \~chinese + /// @brief 获取平移最小限制 + float GetLowerLimit() const; + + /// \~chinese + /// @brief 获取平移最大限制 + float GetUpperLimit() const; + + /// \~chinese + /// @brief 设置关节限制 + void SetLimits(float lower, float upper); + + /// \~chinese + /// @brief 是否启用马达 + bool IsMotorEnabled() const; + + /// \~chinese + /// @brief 设置是否启用马达 + void EnableMotor(bool flag); + + /// \~chinese + /// @brief 设置马达转速 [degree/s] + void SetMotorSpeed(float speed); + + /// \~chinese + /// @brief 获取马达转速 [degree/s] + float GetMotorSpeed() const; + + /// \~chinese + /// @brief 设置最大马达力 [N] + void SetMaxMotorForce(float force); + + /// \~chinese + /// @brief 获取最大马达力 [N] + float GetMaxMotorForce() const; + +private: + b2PrismaticJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 滑轮关节 +class KGE_API PulleyJoint : public Joint +{ +public: + /// \~chinese + /// @brief 滑轮关节参数 + struct Param : public Joint::ParamBase + { + Point anchor_a; ///< 关节在物体A上的作用点 + Point anchor_b; ///< 关节在物体B上的作用点 + Point ground_anchor_a; ///< 物体A对应的滑轮的位置 + Point ground_anchor_b; ///< 物体B对应的滑轮的位置 + float ratio; ///< 滑轮比,关节传动时,滑轮上升和下降的两头的位移比例 + + Param(Body* body_a, Body* body_b, Point const& anchor_a, Point const& anchor_b, Point const& ground_anchor_a, + Point const& ground_anchor_b, float ratio = 1.0f) + : ParamBase(body_a, body_b) + , anchor_a(anchor_a) + , anchor_b(anchor_b) + , ground_anchor_a(ground_anchor_a) + , ground_anchor_b(ground_anchor_b) + , ratio(ratio) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor_a, Point const& anchor_b, + Point const& ground_anchor_a, Point const& ground_anchor_b, float ratio = 1.0f) + : Param(body_a.get(), body_b.get(), anchor_a, anchor_b, ground_anchor_a, ground_anchor_b, ratio) + { + } + }; + + PulleyJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 物体A对应的滑轮的位置 + Point GetGroundAnchorA() const; + + /// \~chinese + /// @brief 物体B对应的滑轮的位置 + Point GetGroundAnchorB() const; + + /// \~chinese + /// @brief 获取滑轮传动比 + float GetRatio() const; + + /// \~chinese + /// @brief 获取物体A与滑轮的距离 + float GetLengthA() const; + + /// \~chinese + /// @brief 获取物体B与滑轮的距离 + float GetLengthB() const; + + /// \~chinese + /// @brief 获取物体A与滑轮的当前距离 + float GetCurrentLengthA() const; + + /// \~chinese + /// @brief 获取物体B与滑轮的当前距离 + float GetCurrentLengthB() const; + +private: + b2PulleyJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 旋转关节 +class KGE_API RevoluteJoint : public Joint +{ +public: + /// \~chinese + /// @brief 旋转关节参数 + struct Param : public Joint::ParamBase + { + Point anchor; ///< 关节位置 + bool enable_limit; ///< 是否启用限制 + float lower_angle; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 + float upper_angle; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 + bool enable_motor; ///< 是否启用马达 + float max_motor_torque; ///< 最大马达力 [N] + float motor_speed; ///< 马达转速 [degree/s] + + Param(Body* body_a, Body* body_b, Point const& anchor, bool enable_limit = false, float lower_angle = 0.0f, + float upper_angle = 0.0f, bool enable_motor = false, float max_motor_torque = 0.0f, + float motor_speed = 0.0f) + : ParamBase(body_a, body_b) + , anchor(anchor) + , enable_limit(enable_limit) + , lower_angle(lower_angle) + , upper_angle(upper_angle) + , enable_motor(enable_motor) + , max_motor_torque(max_motor_torque) + , motor_speed(motor_speed) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, bool enable_limit = false, float lower_angle = 0.0f, + float upper_angle = 0.0f, bool enable_motor = false, float max_motor_torque = 0.0f, + float motor_speed = 0.0f) + : Param(body_a.get(), body_b.get(), anchor, enable_limit, lower_angle, upper_angle, enable_motor, + max_motor_torque, motor_speed) + { + } + }; + + RevoluteJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 获取参考角 + float GetReferenceAngle() const; + + /// \~chinese + /// @brief 获取关节角度 + float GetJointAngle() const; + + /// \~chinese + /// @brief 获取关节速度 + float GetJointSpeed() const; + + /// \~chinese + /// @brief 是否启用关节限制 + bool IsLimitEnabled() const; + + /// \~chinese + /// @brief 设置是否启用关节限制 + void EnableLimit(bool flag); + + /// \~chinese + /// @brief 获取平移最小限制 + float GetLowerLimit() const; + + /// \~chinese + /// @brief 获取平移最大限制 + float GetUpperLimit() const; + + /// \~chinese + /// @brief 设置关节限制 + void SetLimits(float lower, float upper); + + /// \~chinese + /// @brief 是否启用马达 + bool IsMotorEnabled() const; + + /// \~chinese + /// @brief 设置是否启用马达 + void EnableMotor(bool flag); + + /// \~chinese + /// @brief 设置马达转速 [degree/s] + void SetMotorSpeed(float speed); + + /// \~chinese + /// @brief 获取马达转速 [degree/s] + float GetMotorSpeed() const; + + /// \~chinese + /// @brief 设置最大马达转矩 [N/m] + void SetMaxMotorTorque(float torque); + + /// \~chinese + /// @brief 获取最大马达转矩 [N/m] + float GetMaxMotorTorque() const; + +private: + b2RevoluteJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 绳关节 +class KGE_API RopeJoint : public Joint +{ +public: + /// \~chinese + /// @brief 绳关节参数 + struct Param : public Joint::ParamBase + { + Point local_anchor_a; ///< 关节在物体A上的连接点 + Point local_anchor_b; ///< 关节在物体B上的连接点 + float max_length; ///< 绳索最大长度 + + Param(Body* body_a, Body* body_b, Point const& local_anchor_a, Point const& local_anchor_b, + float max_length = 0.f) + : ParamBase(body_a, body_b) + , local_anchor_a(local_anchor_a) + , local_anchor_b(local_anchor_b) + , max_length(max_length) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& local_anchor_a, Point const& local_anchor_b, + float max_length = 0.f) + : Param(body_a.get(), body_b.get(), local_anchor_a, local_anchor_b, max_length) + { + } + }; + + RopeJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 设置关节最大长度 + void SetMaxLength(float length); + + /// \~chinese + /// @brief 获取关节最大长度 + float GetMaxLength() const; + +private: + b2RopeJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 焊接关节 +class KGE_API WeldJoint : public Joint +{ +public: + /// \~chinese + /// @brief 焊接关节参数 + struct Param : public Joint::ParamBase + { + Point anchor; ///< 焊接位置 + float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 + float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 + + Param(Body* body_a, Body* body_b, Point const& anchor, float frequency_hz = 0.f, float damping_ratio = 0.f) + : ParamBase(body_a, body_b) + , anchor(anchor) + , frequency_hz(frequency_hz) + , damping_ratio(damping_ratio) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, float frequency_hz = 0.f, float damping_ratio = 0.f) + : Param(body_a.get(), body_b.get(), anchor, frequency_hz, damping_ratio) + { + } + }; + + WeldJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 获取物体B相对于物体A的角度 + float GetReferenceAngle() const; + + /// \~chinese + /// @brief 设置弹簧响应速度 [赫兹] + void SetFrequency(float hz); + + /// \~chinese + /// @brief 获取弹簧响应速度 [赫兹] + float GetFrequency() const; + + /// \~chinese + /// @brief 设置阻尼率 + void SetDampingRatio(float ratio); + + /// \~chinese + /// @brief 获取阻尼率 + float GetDampingRatio() const; + +private: + b2WeldJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 轮关节 +class KGE_API WheelJoint : public Joint +{ +public: + /// \~chinese + /// @brief 轮关节参数 + struct Param : public Joint::ParamBase + { + Point anchor; ///< 轮关节位置 + Vec2 axis; ///< 物体A滑动方向 + bool enable_motor; ///< 是否启用马达 + float max_motor_torque; ///< 最大马达力 [N] + float motor_speed; ///< 马达转速 [degree/s] + float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 + float damping_ratio; ///< 弹簧阻尼率,值越大关节运动阻尼越大 + + Param(Body* body_a, Body* body_b, Point const& anchor, Vec2 const& axis, float frequency_hz = 2.0f, + float damping_ratio = 0.7f, bool enable_motor = false, float max_motor_torque = 0.0f, + float motor_speed = 0.0f) + : ParamBase(body_a, body_b) + , anchor(anchor) + , axis(axis) + , enable_motor(enable_motor) + , max_motor_torque(max_motor_torque) + , motor_speed(motor_speed) + , frequency_hz(frequency_hz) + , damping_ratio(damping_ratio) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, Vec2 const& axis, float frequency_hz = 2.0f, + float damping_ratio = 0.7f, bool enable_motor = false, float max_motor_torque = 0.0f, + float motor_speed = 0.0f) + : Param(body_a.get(), body_b.get(), anchor, axis, frequency_hz, damping_ratio, enable_motor, + max_motor_torque, motor_speed) + { + } + }; + + WheelJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 获取关节当前的平移距离 + float GetJointTranslation() const; + + /// \~chinese + /// @brief 获取关节当前的线性速度 + float GetJointLinearSpeed() const; + + /// \~chinese + /// @brief 获取关节当前的角度 + float GetJointAngle() const; + + /// \~chinese + /// @brief 获取关节当前的旋转速度 + float GetJointAngularSpeed() const; + + /// \~chinese + /// @brief 是否启用马达 + bool IsMotorEnabled() const; + + /// \~chinese + /// @brief 设置是否启用马达 + void EnableMotor(bool flag); + + /// \~chinese + /// @brief 设置马达转速 [degree/s] + void SetMotorSpeed(float speed); + + /// \~chinese + /// @brief 获取马达转速 [degree/s] + float GetMotorSpeed() const; + + /// \~chinese + /// @brief 设置最大马达转矩 [N/m] + void SetMaxMotorTorque(float torque); + + /// \~chinese + /// @brief 获取最大马达转矩 [N/m] + float GetMaxMotorTorque() const; + + /// \~chinese + /// @brief 设置弹簧响应速度 + void SetSpringFrequencyHz(float hz); + + /// \~chinese + /// @brief 获取弹簧响应速度 + float GetSpringFrequencyHz() const; + + /// \~chinese + /// @brief 设置弹簧阻尼率 + void SetSpringDampingRatio(float ratio); + + /// \~chinese + /// @brief 获取弹簧阻尼率 + float GetSpringDampingRatio() const; + +private: + b2WheelJoint* raw_joint_; +}; + +/// \~chinese +/// @brief 鼠标关节 +/// @details 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置 +class KGE_API MouseJoint : public Joint +{ +public: + /// \~chinese + /// @brief 鼠标关节参数 + struct Param : public Joint::ParamBase + { + Point target; ///< 关节作用目标位置 + float max_force; ///< 作用在物体A上的最大力 + float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 + float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 + + Param(Body* body_a, Body* body_b, Point const& target, float max_force, float frequency_hz = 5.0f, + float damping_ratio = 0.7f) + : ParamBase(body_a, body_b) + , target(target) + , max_force(max_force) + , frequency_hz(frequency_hz) + , damping_ratio(damping_ratio) + { + } + + Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f, + float damping_ratio = 0.7f) + : Param(body_a.get(), body_b.get(), target, max_force, frequency_hz, damping_ratio) + { + } + }; + + MouseJoint(); + + /// \~chinese + /// @brief 初始化关节 + bool InitJoint(World* world, Param const& param); + + /// \~chinese + /// @brief 设定最大摩擦力 [N] + void SetMaxForce(float force); + + /// \~chinese + /// @brief 获取最大摩擦力 [N] + float GetMaxForce() const; + + /// \~chinese + /// @brief 设置响应速度 [hz] + void SetFrequency(float hz); + + /// \~chinese + /// @brief 获取响应速度 [hz] + float GetFrequency() const; + + /// \~chinese + /// @brief 设置阻尼率 + void SetDampingRatio(float ratio); + + /// \~chinese + /// @brief 获取阻尼率 + float GetDampingRatio() const; + +private: + b2MouseJoint* raw_joint_; +}; + +/** @} */ + +inline b2Joint* Joint::GetB2Joint() const +{ + return joint_; } +inline World* Joint::GetWorld() const +{ + return world_; +} + +inline void DistanceJoint::SetFrequency(float hz) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetFrequency(hz); +} +inline float DistanceJoint::GetFrequency() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetFrequency(); +} +inline void DistanceJoint::SetDampingRatio(float ratio) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetDampingRatio(ratio); +} +inline float DistanceJoint::GetDampingRatio() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetDampingRatio(); +} + +inline float PrismaticJoint::GetReferenceAngle() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetReferenceAngle()); +} +inline bool PrismaticJoint::IsLimitEnabled() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->IsLimitEnabled(); +} +inline void PrismaticJoint::EnableLimit(bool flag) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->EnableLimit(flag); +} +inline bool PrismaticJoint::IsMotorEnabled() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->IsMotorEnabled(); +} +inline void PrismaticJoint::EnableMotor(bool flag) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->EnableMotor(flag); +} +inline void PrismaticJoint::SetMotorSpeed(float speed) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); +} +inline float PrismaticJoint::GetMotorSpeed() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetMotorSpeed()); +} +inline void PrismaticJoint::SetMaxMotorForce(float force) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxMotorForce(force); +} +inline float PrismaticJoint::GetMaxMotorForce() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetMaxMotorForce(); +} + +inline float RevoluteJoint::GetReferenceAngle() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetReferenceAngle()); +} +inline bool RevoluteJoint::IsLimitEnabled() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->IsLimitEnabled(); +} +inline void RevoluteJoint::EnableLimit(bool flag) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->EnableLimit(flag); +} +inline bool RevoluteJoint::IsMotorEnabled() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->IsMotorEnabled(); +} +inline void RevoluteJoint::EnableMotor(bool flag) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->EnableMotor(flag); +} +inline void RevoluteJoint::SetMotorSpeed(float speed) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); +} +inline float RevoluteJoint::GetMotorSpeed() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetMotorSpeed()); +} + +inline float WeldJoint::GetReferenceAngle() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetReferenceAngle()); +} +inline void WeldJoint::SetFrequency(float hz) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetFrequency(hz); +} +inline float WeldJoint::GetFrequency() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetFrequency(); +} +inline void WeldJoint::SetDampingRatio(float ratio) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetDampingRatio(ratio); +} +inline float WeldJoint::GetDampingRatio() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetDampingRatio(); +} + +inline float WheelJoint::GetJointAngle() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetJointAngle()); +} +inline float WheelJoint::GetJointAngularSpeed() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); +} +inline bool WheelJoint::IsMotorEnabled() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->IsMotorEnabled(); +} +inline void WheelJoint::EnableMotor(bool flag) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->EnableMotor(flag); +} +inline void WheelJoint::SetMotorSpeed(float speed) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); +} +inline float WheelJoint::GetMotorSpeed() const +{ + KGE_ASSERT(raw_joint_); + return math::Radian2Degree(raw_joint_->GetMotorSpeed()); +} +inline void WheelJoint::SetSpringFrequencyHz(float hz) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetSpringFrequencyHz(hz); +} +inline float WheelJoint::GetSpringFrequencyHz() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetSpringFrequencyHz(); +} +inline void WheelJoint::SetSpringDampingRatio(float ratio) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetSpringDampingRatio(ratio); +} +inline float WheelJoint::GetSpringDampingRatio() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetSpringDampingRatio(); +} + +inline void MouseJoint::SetFrequency(float hz) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetFrequency(hz); +} +inline float MouseJoint::GetFrequency() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetFrequency(); +} +inline void MouseJoint::SetDampingRatio(float ratio) +{ + KGE_ASSERT(raw_joint_); + raw_joint_->SetDampingRatio(ratio); +} +inline float MouseJoint::GetDampingRatio() const +{ + KGE_ASSERT(raw_joint_); + return raw_joint_->GetDampingRatio(); +} +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/Shape.cpp b/src/kiwano-physics/Shape.cpp index d39a49e1..709bf2c3 100644 --- a/src/kiwano-physics/Shape.cpp +++ b/src/kiwano-physics/Shape.cpp @@ -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 const& vertexs) - : PolygonShape() - { - Set(vertexs); - } - - void PolygonShape::Set(Vector const& vertexs) - { - vertexs_ = vertexs; - } - - void PolygonShape::FitWorld(World* world) - { - KGE_ASSERT(world); - - Vector b2vertexs; - b2vertexs.reserve(vertexs_.size()); - for (const auto& v : vertexs_) - { - b2vertexs.push_back(world->Stage2World(v)); - } - - polygon_.Set(&b2vertexs[0], static_cast(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 const& vertexs, bool loop) - : ChainShape() - { - Set(vertexs, loop); - } - - void ChainShape::Set(Vector const& vertexs, bool loop) - { - vertexs_ = vertexs; - loop_ = loop; - } - - void ChainShape::FitWorld(World* world) - { - KGE_ASSERT(world); - - Vector b2vertexs; - b2vertexs.reserve(vertexs_.size()); - for (const auto& v : vertexs_) - { - b2vertexs.push_back(world->Stage2World(v)); - } - - if (loop_) - { - chain_.CreateLoop(&b2vertexs[0], static_cast(b2vertexs.size())); - } - else - { - chain_.CreateChain(&b2vertexs[0], static_cast(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 const& vertexs) + : PolygonShape() +{ + Set(vertexs); +} + +void PolygonShape::Set(Vector const& vertexs) +{ + vertexs_ = vertexs; +} + +void PolygonShape::FitWorld(World* world) +{ + KGE_ASSERT(world); + + Vector b2vertexs; + b2vertexs.reserve(vertexs_.size()); + for (const auto& v : vertexs_) + { + b2vertexs.push_back(world->Stage2World(v)); + } + + polygon_.Set(&b2vertexs[0], static_cast(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 const& vertexs, bool loop) + : ChainShape() +{ + Set(vertexs, loop); +} + +void ChainShape::Set(Vector const& vertexs, bool loop) +{ + vertexs_ = vertexs; + loop_ = loop; +} + +void ChainShape::FitWorld(World* world) +{ + KGE_ASSERT(world); + + Vector b2vertexs; + b2vertexs.reserve(vertexs_.size()); + for (const auto& v : vertexs_) + { + b2vertexs.push_back(world->Stage2World(v)); + } + + if (loop_) + { + chain_.CreateLoop(&b2vertexs[0], static_cast(b2vertexs.size())); + } + else + { + chain_.CreateChain(&b2vertexs[0], static_cast(b2vertexs.size())); + } +} + +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/Shape.h b/src/kiwano-physics/Shape.h index 8ee206f1..b6f7e9fa 100644 --- a/src/kiwano-physics/Shape.h +++ b/src/kiwano-physics/Shape.h @@ -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 const& vertexs); + PolygonShape(Vector const& vertexs); - void Set(Vector const& vertexs); + void Set(Vector const& vertexs); - private: - void FitWorld(World* world) override; +private: + void FitWorld(World* world) override; - private: - Vector vertexs_; - b2PolygonShape polygon_; - }; +private: + Vector 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 const& vertexs, bool loop = false); + ChainShape(Vector const& vertexs, bool loop = false); - void Set(Vector const& vertexs, bool loop = false); + void Set(Vector const& vertexs, bool loop = false); - private: - void FitWorld(World* world) override; +private: + void FitWorld(World* world) override; - private: - bool loop_; - Vector vertexs_; - b2ChainShape chain_; - }; +private: + bool loop_; + Vector vertexs_; + b2ChainShape chain_; +}; - /** @} */ - } -} +/** @} */ +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/World.cpp b/src/kiwano-physics/World.cpp index 99cf93bf..31b981da 100644 --- a/src/kiwano-physics/World.cpp +++ b/src/kiwano-physics/World.cpp @@ -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 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(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(b2body->GetUserData()); + if (body && body->GetType() != Body::Type::Static) + { + body->UpdateActor(); + } + + b2body = b2body->GetNext(); + } + + Stage::Update(dt); +} + +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/World.h b/src/kiwano-physics/World.h index ef5914c2..335f5069 100644 --- a/src/kiwano-physics/World.h +++ b/src/kiwano-physics/World.h @@ -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 joints_; - }; + bool removing_joint_; + Vector 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 diff --git a/src/kiwano-physics/helper.h b/src/kiwano-physics/helper.h index 3436b0a1..f3be4fbf 100644 --- a/src/kiwano-physics/helper.h +++ b/src/kiwano-physics/helper.h @@ -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 diff --git a/src/kiwano-physics/kiwano-physics.h b/src/kiwano-physics/kiwano-physics.h index fcc446d2..b10153d3 100644 --- a/src/kiwano-physics/kiwano-physics.h +++ b/src/kiwano-physics/kiwano-physics.h @@ -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 -#include +#include #include #include -#include +#include #include +#include #include diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 0ff27515..73793a26 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -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,634 +25,633 @@ namespace kiwano { - namespace - { - float default_anchor_x = 0.f; - float default_anchor_y = 0.f; - } - - void Actor::SetDefaultAnchor(float anchor_x, float anchor_y) - { - default_anchor_x = anchor_x; - default_anchor_y = anchor_y; - } - - Actor::Actor() - : visible_(true) - , visible_in_rt_(true) - , update_pausing_(false) - , hover_(false) - , pressed_(false) - , responsible_(false) - , dirty_visibility_(true) - , dirty_transform_(false) - , dirty_transform_inverse_(false) - , cascade_opacity_(false) - , show_border_(false) - , is_fast_transform_(true) - , parent_(nullptr) - , stage_(nullptr) - , hash_name_(0) - , z_order_(0) - , opacity_(1.f) - , displayed_opacity_(1.f) - , anchor_(default_anchor_x, default_anchor_y) - { - } - - Actor::~Actor() - { - } - - void Actor::Update(Duration dt) - { - UpdateActions(this, dt); - UpdateTimers(dt); - - if (!update_pausing_) - { - if (cb_update_) - cb_update_(dt); - - OnUpdate(dt); - } - - if (!children_.empty()) - { - ActorPtr next; - for (auto child = children_.first_item(); child; child = next) - { - next = child->next_item(); - child->Update(dt); - } - } - } - - void Actor::Render(RenderContext& ctx) - { - if (!visible_) - return; - - UpdateTransform(); - - if (children_.empty()) - { - if (CheckVisibility(ctx)) - { - PrepareToRender(ctx); - OnRender(ctx); - } - } - else - { - // render children those are less than 0 in Z-Order - Actor* child = children_.first_item().get(); - while (child) - { - if (child->GetZOrder() >= 0) - break; - - child->Render(ctx); - child = child->next_item().get(); - } - - if (CheckVisibility(ctx)) - { - PrepareToRender(ctx); - OnRender(ctx); - } - - while (child) - { - child->Render(ctx); - child = child->next_item().get(); - } - } - } - - void Actor::PrepareToRender(RenderContext& ctx) - { - ctx.SetTransform(transform_matrix_); - ctx.SetBrushOpacity(GetDisplayedOpacity()); - } - - void Actor::RenderBorder(RenderContext& ctx) - { - if (show_border_ && !size_.IsOrigin()) - { - Rect bounds = GetBounds(); - - ctx.SetTransform(transform_matrix_); - - ctx.SetCurrentBrush(GetStage()->GetBorderFillBrush()); - ctx.FillRectangle(bounds); - - ctx.SetCurrentBrush(GetStage()->GetBorderStrokeBrush()); - ctx.DrawRectangle(bounds, 2.f); - } - - for (auto child = children_.first_item(); child; child = child->next_item()) - { - child->RenderBorder(ctx); - } - } - - bool Actor::CheckVisibility(RenderContext& ctx) const - { - if (dirty_visibility_) - { - dirty_visibility_ = false; - - if (size_.IsOrigin()) - { - visible_in_rt_ = false; - } - else - { - visible_in_rt_ = ctx.CheckVisibility(GetBounds(), GetTransformMatrix()); - } - } - return visible_in_rt_; - } - - bool Actor::DispatchEvent(Event* evt) - { - if (!visible_) - return true; - - // Dispatch to children those are greater than 0 in Z-Order - Actor* child = children_.last_item().get(); - while (child) - { - if (child->GetZOrder() < 0) - break; - - if (!child->DispatchEvent(evt)) - return false; - - child = child->prev_item().get(); - } - - if (!EventDispatcher::DispatchEvent(evt)) - return false; - - HandleEvent(evt); - - while (child) - { - if (!child->DispatchEvent(evt)) - return false; - - child = child->prev_item().get(); - } - return true; - } - - void Actor::HandleEvent(Event* evt) - { - if (responsible_) - { - if (evt->IsType()) - { - auto mouse_evt = dynamic_cast(evt); - bool contains = ContainsPoint(mouse_evt->pos); - if (!hover_ && contains) - { - hover_ = true; - - MouseHoverEventPtr hover = new MouseHoverEvent; - hover->pos = mouse_evt->pos; - EventDispatcher::DispatchEvent(hover.get()); - } - else if (hover_ && !contains) - { - hover_ = false; - pressed_ = false; - - MouseOutEventPtr out = new MouseOutEvent; - out->pos = mouse_evt->pos; - EventDispatcher::DispatchEvent(out.get()); - } - } - - if (evt->IsType() && hover_) - { - pressed_ = true; - } - - if (evt->IsType() && pressed_) - { - pressed_ = false; - - auto mouse_up_evt = dynamic_cast(evt); - - MouseClickEventPtr click = new MouseClickEvent; - click->pos = mouse_up_evt->pos; - click->button = mouse_up_evt->button; - EventDispatcher::DispatchEvent(click.get()); - } - } - } - - Matrix3x2 const & Actor::GetTransformMatrix() const - { - UpdateTransform(); - return transform_matrix_; - } - - Matrix3x2 const & Actor::GetTransformInverseMatrix() const - { - UpdateTransform(); - if (dirty_transform_inverse_) - { - transform_matrix_inverse_ = transform_matrix_.Invert(); - dirty_transform_inverse_ = false; - } - return transform_matrix_inverse_; - } - - void Actor::UpdateTransform() const - { - if (!dirty_transform_) - return; - - dirty_transform_ = false; - dirty_transform_inverse_ = true; - dirty_visibility_ = true; - - if (is_fast_transform_) - { - transform_matrix_ = Matrix3x2::Translation(transform_.position); - } - else - { - // matrix multiplication is optimized by expression template - transform_matrix_ = transform_.ToMatrix(); - } - - transform_matrix_.Translate(Point{ -size_.x * anchor_.x, -size_.y * anchor_.y }); - - if (parent_) - { - transform_matrix_ *= parent_->transform_matrix_; - } - - // update children's transform - for (auto child = children_.first_item().get(); child; child = child->next_item().get()) - child->dirty_transform_ = true; - } - - void Actor::UpdateOpacity() - { - if (parent_ && parent_->IsCascadeOpacityEnabled()) - { - displayed_opacity_ = opacity_ * parent_->displayed_opacity_; - } - else - { - displayed_opacity_ = opacity_; - } - - for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) - { - child->UpdateOpacity(); - } - } - - void Actor::SetStage(Stage* stage) - { - if (stage_ != stage) - { - stage_ = stage; - for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) - { - child->stage_ = stage; - } - } - } - - void Actor::Reorder() - { - if (parent_) - { - ActorPtr me = this; - - parent_->children_.remove(me); - - Actor* sibling = parent_->children_.last_item().get(); - - if (sibling && sibling->GetZOrder() > z_order_) - { - sibling = sibling->prev_item().get(); - while (sibling) - { - if (sibling->GetZOrder() <= z_order_) - break; - sibling = sibling->prev_item().get(); - } - } - - if (sibling) - { - parent_->children_.insert_after(me, sibling); - } - else - { - parent_->children_.push_front(me); - } - } - } - - void Actor::SetZOrder(int zorder) - { - if (z_order_ != zorder) - { - z_order_ = zorder; - Reorder(); - } - } - - void Actor::SetOpacity(float opacity) - { - if (opacity_ == opacity) - return; - - displayed_opacity_ = opacity_ = std::min(std::max(opacity, 0.f), 1.f); - UpdateOpacity(); - } - - void Actor::SetCascadeOpacityEnabled(bool enabled) - { - if (cascade_opacity_ == enabled) - return; - - cascade_opacity_ = enabled; - UpdateOpacity(); - } - - void Actor::SetAnchor(Vec2 const& anchor) - { - if (anchor_ == anchor) - return; - - anchor_ = anchor; - dirty_transform_ = true; - } - - void Actor::SetWidth(float width) - { - SetSize(Size{ width, size_.y }); - } - - void Actor::SetHeight(float height) - { - SetSize(Size{ size_.x, height }); - } - - void Actor::SetSize(Size const& size) - { - if (size_ == size) - return; - - size_ = size; - dirty_transform_ = true; - } - - void Actor::SetTransform(Transform const& transform) - { - transform_ = transform; - dirty_transform_ = true; - is_fast_transform_ = false; - } - - void Actor::SetVisible(bool val) - { - visible_ = val; - } - - void Actor::SetName(String const& name) - { - if (!IsName(name)) - { - ObjectBase::SetName(name); - hash_name_ = std::hash{}(name); - } - } - - void Actor::SetPosition(const Point & pos) - { - if (transform_.position == pos) - return; - - transform_.position = pos; - dirty_transform_ = true; - } - - void Actor::SetPositionX(float x) - { - SetPosition(Point{ x, transform_.position.y }); - } - - void Actor::SetPositionY(float y) - { - SetPosition(Point{ transform_.position.x, y }); - } - - void Actor::Move(Vec2 const& v) - { - this->SetPosition(Point{ transform_.position.x + v.x, transform_.position.y + v.y }); - } - - void Actor::SetScale(Vec2 const& scale) - { - if (transform_.scale == scale) - return; - - transform_.scale = scale; - dirty_transform_ = true; - is_fast_transform_ = false; - } - - void Actor::SetSkew(Vec2 const& skew) - { - if (transform_.skew == skew) - return; - - transform_.skew = skew; - dirty_transform_ = true; - is_fast_transform_ = false; - } - - void Actor::SetRotation(float angle) - { - if (transform_.rotation == angle) - return; - - transform_.rotation = angle; - dirty_transform_ = true; - is_fast_transform_ = false; - } - - void Actor::AddChild(Actor* child, int zorder) - { - KGE_ASSERT(child && "Actor::AddChild failed, NULL pointer exception"); - - if (child) - { - KGE_ASSERT(!child->parent_ && "Actor::AddChild failed, the actor to be added already has a parent"); +namespace +{ +float default_anchor_x = 0.f; +float default_anchor_y = 0.f; +} // namespace + +void Actor::SetDefaultAnchor(float anchor_x, float anchor_y) +{ + default_anchor_x = anchor_x; + default_anchor_y = anchor_y; +} + +Actor::Actor() + : visible_(true) + , visible_in_rt_(true) + , update_pausing_(false) + , hover_(false) + , pressed_(false) + , responsible_(false) + , dirty_visibility_(true) + , dirty_transform_(false) + , dirty_transform_inverse_(false) + , cascade_opacity_(false) + , show_border_(false) + , is_fast_transform_(true) + , parent_(nullptr) + , stage_(nullptr) + , hash_name_(0) + , z_order_(0) + , opacity_(1.f) + , displayed_opacity_(1.f) + , anchor_(default_anchor_x, default_anchor_y) +{ +} + +Actor::~Actor() {} + +void Actor::Update(Duration dt) +{ + UpdateActions(this, dt); + UpdateTimers(dt); + + if (!update_pausing_) + { + if (cb_update_) + cb_update_(dt); + + OnUpdate(dt); + } + + if (!children_.empty()) + { + ActorPtr next; + for (auto child = children_.first_item(); child; child = next) + { + next = child->next_item(); + child->Update(dt); + } + } +} + +void Actor::Render(RenderContext& ctx) +{ + if (!visible_) + return; + + UpdateTransform(); + + if (children_.empty()) + { + if (CheckVisibility(ctx)) + { + PrepareToRender(ctx); + OnRender(ctx); + } + } + else + { + // render children those are less than 0 in Z-Order + Actor* child = children_.first_item().get(); + while (child) + { + if (child->GetZOrder() >= 0) + break; + + child->Render(ctx); + child = child->next_item().get(); + } + + if (CheckVisibility(ctx)) + { + PrepareToRender(ctx); + OnRender(ctx); + } + + while (child) + { + child->Render(ctx); + child = child->next_item().get(); + } + } +} + +void Actor::PrepareToRender(RenderContext& ctx) +{ + ctx.SetTransform(transform_matrix_); + ctx.SetBrushOpacity(GetDisplayedOpacity()); +} + +void Actor::RenderBorder(RenderContext& ctx) +{ + if (show_border_ && !size_.IsOrigin()) + { + Rect bounds = GetBounds(); + + ctx.SetTransform(transform_matrix_); + + ctx.SetCurrentBrush(GetStage()->GetBorderFillBrush()); + ctx.FillRectangle(bounds); + + ctx.SetCurrentBrush(GetStage()->GetBorderStrokeBrush()); + ctx.DrawRectangle(bounds, 2.f); + } + + for (auto child = children_.first_item(); child; child = child->next_item()) + { + child->RenderBorder(ctx); + } +} + +bool Actor::CheckVisibility(RenderContext& ctx) const +{ + if (dirty_visibility_) + { + dirty_visibility_ = false; + + if (size_.IsOrigin()) + { + visible_in_rt_ = false; + } + else + { + visible_in_rt_ = ctx.CheckVisibility(GetBounds(), GetTransformMatrix()); + } + } + return visible_in_rt_; +} + +bool Actor::DispatchEvent(Event* evt) +{ + if (!visible_) + return true; + + // Dispatch to children those are greater than 0 in Z-Order + Actor* child = children_.last_item().get(); + while (child) + { + if (child->GetZOrder() < 0) + break; + + if (!child->DispatchEvent(evt)) + return false; + + child = child->prev_item().get(); + } + + if (!EventDispatcher::DispatchEvent(evt)) + return false; + + HandleEvent(evt); + + while (child) + { + if (!child->DispatchEvent(evt)) + return false; + + child = child->prev_item().get(); + } + return true; +} + +void Actor::HandleEvent(Event* evt) +{ + if (responsible_) + { + if (evt->IsType()) + { + auto mouse_evt = dynamic_cast(evt); + bool contains = ContainsPoint(mouse_evt->pos); + if (!hover_ && contains) + { + hover_ = true; + + MouseHoverEventPtr hover = new MouseHoverEvent; + hover->pos = mouse_evt->pos; + EventDispatcher::DispatchEvent(hover.get()); + } + else if (hover_ && !contains) + { + hover_ = false; + pressed_ = false; + + MouseOutEventPtr out = new MouseOutEvent; + out->pos = mouse_evt->pos; + EventDispatcher::DispatchEvent(out.get()); + } + } + + if (evt->IsType() && hover_) + { + pressed_ = true; + } + + if (evt->IsType() && pressed_) + { + pressed_ = false; + + auto mouse_up_evt = dynamic_cast(evt); + + MouseClickEventPtr click = new MouseClickEvent; + click->pos = mouse_up_evt->pos; + click->button = mouse_up_evt->button; + EventDispatcher::DispatchEvent(click.get()); + } + } +} + +Matrix3x2 const& Actor::GetTransformMatrix() const +{ + UpdateTransform(); + return transform_matrix_; +} + +Matrix3x2 const& Actor::GetTransformInverseMatrix() const +{ + UpdateTransform(); + if (dirty_transform_inverse_) + { + transform_matrix_inverse_ = transform_matrix_.Invert(); + dirty_transform_inverse_ = false; + } + return transform_matrix_inverse_; +} + +void Actor::UpdateTransform() const +{ + if (!dirty_transform_) + return; + + dirty_transform_ = false; + dirty_transform_inverse_ = true; + dirty_visibility_ = true; + + if (is_fast_transform_) + { + transform_matrix_ = Matrix3x2::Translation(transform_.position); + } + else + { + // matrix multiplication is optimized by expression template + transform_matrix_ = transform_.ToMatrix(); + } + + transform_matrix_.Translate(Point{ -size_.x * anchor_.x, -size_.y * anchor_.y }); + + if (parent_) + { + transform_matrix_ *= parent_->transform_matrix_; + } + + // update children's transform + for (auto child = children_.first_item().get(); child; child = child->next_item().get()) + child->dirty_transform_ = true; +} + +void Actor::UpdateOpacity() +{ + if (parent_ && parent_->IsCascadeOpacityEnabled()) + { + displayed_opacity_ = opacity_ * parent_->displayed_opacity_; + } + else + { + displayed_opacity_ = opacity_; + } + + for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) + { + child->UpdateOpacity(); + } +} + +void Actor::SetStage(Stage* stage) +{ + if (stage_ != stage) + { + stage_ = stage; + for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) + { + child->stage_ = stage; + } + } +} + +void Actor::Reorder() +{ + if (parent_) + { + ActorPtr me = this; + + parent_->children_.remove(me); + + Actor* sibling = parent_->children_.last_item().get(); + + if (sibling && sibling->GetZOrder() > z_order_) + { + sibling = sibling->prev_item().get(); + while (sibling) + { + if (sibling->GetZOrder() <= z_order_) + break; + sibling = sibling->prev_item().get(); + } + } + + if (sibling) + { + parent_->children_.insert_after(me, sibling); + } + else + { + parent_->children_.push_front(me); + } + } +} + +void Actor::SetZOrder(int zorder) +{ + if (z_order_ != zorder) + { + z_order_ = zorder; + Reorder(); + } +} + +void Actor::SetOpacity(float opacity) +{ + if (opacity_ == opacity) + return; + + displayed_opacity_ = opacity_ = std::min(std::max(opacity, 0.f), 1.f); + UpdateOpacity(); +} + +void Actor::SetCascadeOpacityEnabled(bool enabled) +{ + if (cascade_opacity_ == enabled) + return; + + cascade_opacity_ = enabled; + UpdateOpacity(); +} + +void Actor::SetAnchor(Vec2 const& anchor) +{ + if (anchor_ == anchor) + return; + + anchor_ = anchor; + dirty_transform_ = true; +} + +void Actor::SetWidth(float width) +{ + SetSize(Size{ width, size_.y }); +} + +void Actor::SetHeight(float height) +{ + SetSize(Size{ size_.x, height }); +} + +void Actor::SetSize(Size const& size) +{ + if (size_ == size) + return; + + size_ = size; + dirty_transform_ = true; +} + +void Actor::SetTransform(Transform const& transform) +{ + transform_ = transform; + dirty_transform_ = true; + is_fast_transform_ = false; +} + +void Actor::SetVisible(bool val) +{ + visible_ = val; +} + +void Actor::SetName(String const& name) +{ + if (!IsName(name)) + { + ObjectBase::SetName(name); + hash_name_ = std::hash{}(name); + } +} + +void Actor::SetPosition(const Point& pos) +{ + if (transform_.position == pos) + return; + + transform_.position = pos; + dirty_transform_ = true; +} + +void Actor::SetPositionX(float x) +{ + SetPosition(Point{ x, transform_.position.y }); +} + +void Actor::SetPositionY(float y) +{ + SetPosition(Point{ transform_.position.x, y }); +} + +void Actor::Move(Vec2 const& v) +{ + this->SetPosition(Point{ transform_.position.x + v.x, transform_.position.y + v.y }); +} + +void Actor::SetScale(Vec2 const& scale) +{ + if (transform_.scale == scale) + return; + + transform_.scale = scale; + dirty_transform_ = true; + is_fast_transform_ = false; +} + +void Actor::SetSkew(Vec2 const& skew) +{ + if (transform_.skew == skew) + return; + + transform_.skew = skew; + dirty_transform_ = true; + is_fast_transform_ = false; +} + +void Actor::SetRotation(float angle) +{ + if (transform_.rotation == angle) + return; + + transform_.rotation = angle; + dirty_transform_ = true; + is_fast_transform_ = false; +} + +void Actor::AddChild(Actor* child, int zorder) +{ + KGE_ASSERT(child && "Actor::AddChild failed, NULL pointer exception"); + + if (child) + { + KGE_ASSERT(!child->parent_ && "Actor::AddChild failed, the actor to be added already has a parent"); #ifdef KGE_DEBUG - for (Actor* parent = parent_; parent; parent = parent->parent_) - { - if (parent == child) - { - KGE_ERROR(L"A actor cannot be its own parent"); - return; - } - } + for (Actor* parent = parent_; parent; parent = parent->parent_) + { + if (parent == child) + { + KGE_ERROR(L"A actor cannot be its own parent"); + return; + } + } -#endif // KGE_DEBUG +#endif // KGE_DEBUG - children_.push_back(child); - child->parent_ = this; - child->SetStage(this->stage_); - - child->dirty_transform_ = true; - child->z_order_ = zorder; - child->Reorder(); - child->UpdateOpacity(); - } - } - - void Actor::AddChild(ActorPtr child, int zorder) - { - AddChild(child.get()); - } - - void Actor::AddChildren(Vector const& children) - { - for (const auto& actor : children) - { - this->AddChild(actor); - } - } - - Rect Actor::GetBounds() const - { - return Rect{ Point{}, size_ }; - } - - Rect Actor::GetBoundingBox() const - { - return GetTransformMatrix().Transform(GetBounds()); - } - - Vector Actor::GetChildren(String const& name) const - { - Vector children; - size_t hash_code = std::hash{}(name); - - for (auto child = children_.first_item().get(); child; child = child->next_item().get()) - { - if (child->hash_name_ == hash_code && child->IsName(name)) - { - children.push_back(const_cast(child)); - } - } - return children; - } - - Actor* Actor::GetChild(String const& name) const - { - size_t hash_code = std::hash{}(name); - - for (auto child = children_.first_item().get(); child; child = child->next_item().get()) - { - if (child->hash_name_ == hash_code && child->IsName(name)) - { - return const_cast(child); - } - } - return nullptr; - } - - Actor::Children& Actor::GetAllChildren() - { - return children_; - } - - Actor::Children const & Actor::GetAllChildren() const - { - return children_; - } - - void Actor::RemoveFromParent() - { - if (parent_) - { - parent_->RemoveChild(this); - } - } - - void Actor::RemoveChild(ActorPtr child) - { - RemoveChild(child.get()); - } - - void Actor::RemoveChild(Actor * child) - { - KGE_ASSERT(child && "Actor::RemoveChild failed, NULL pointer exception"); - - if (children_.empty()) - return; - - if (child) - { - child->parent_ = nullptr; - if (child->stage_) child->SetStage(nullptr); - children_.remove(ActorPtr(child)); - } - } - - void Actor::RemoveChildren(String const& child_name) - { - if (children_.empty()) - { - return; - } - - size_t hash_code = std::hash{}(child_name); - - Actor* next; - for (Actor* child = children_.first_item().get(); child; child = next) - { - next = child->next_item().get(); - - if (child->hash_name_ == hash_code && child->IsName(child_name)) - { - RemoveChild(child); - } - } - } - - void Actor::RemoveAllChildren() - { - children_.clear(); - } - - void Actor::SetResponsible(bool enable) - { - responsible_ = enable; - } - - bool Actor::ContainsPoint(const Point& point) const - { - if (size_.x == 0.f || size_.y == 0.f) - return false; - - Point local = GetTransformInverseMatrix().Transform(point); - return GetBounds().ContainsPoint(local); - } + children_.push_back(child); + child->parent_ = this; + child->SetStage(this->stage_); + child->dirty_transform_ = true; + child->z_order_ = zorder; + child->Reorder(); + child->UpdateOpacity(); + } } + +void Actor::AddChild(ActorPtr child, int zorder) +{ + AddChild(child.get()); +} + +void Actor::AddChildren(Vector const& children) +{ + for (const auto& actor : children) + { + this->AddChild(actor); + } +} + +Rect Actor::GetBounds() const +{ + return Rect{ Point{}, size_ }; +} + +Rect Actor::GetBoundingBox() const +{ + return GetTransformMatrix().Transform(GetBounds()); +} + +Vector Actor::GetChildren(String const& name) const +{ + Vector children; + size_t hash_code = std::hash{}(name); + + for (auto child = children_.first_item().get(); child; child = child->next_item().get()) + { + if (child->hash_name_ == hash_code && child->IsName(name)) + { + children.push_back(const_cast(child)); + } + } + return children; +} + +Actor* Actor::GetChild(String const& name) const +{ + size_t hash_code = std::hash{}(name); + + for (auto child = children_.first_item().get(); child; child = child->next_item().get()) + { + if (child->hash_name_ == hash_code && child->IsName(name)) + { + return const_cast(child); + } + } + return nullptr; +} + +Actor::Children& Actor::GetAllChildren() +{ + return children_; +} + +Actor::Children const& Actor::GetAllChildren() const +{ + return children_; +} + +void Actor::RemoveFromParent() +{ + if (parent_) + { + parent_->RemoveChild(this); + } +} + +void Actor::RemoveChild(ActorPtr child) +{ + RemoveChild(child.get()); +} + +void Actor::RemoveChild(Actor* child) +{ + KGE_ASSERT(child && "Actor::RemoveChild failed, NULL pointer exception"); + + if (children_.empty()) + return; + + if (child) + { + child->parent_ = nullptr; + if (child->stage_) + child->SetStage(nullptr); + children_.remove(ActorPtr(child)); + } +} + +void Actor::RemoveChildren(String const& child_name) +{ + if (children_.empty()) + { + return; + } + + size_t hash_code = std::hash{}(child_name); + + Actor* next; + for (Actor* child = children_.first_item().get(); child; child = next) + { + next = child->next_item().get(); + + if (child->hash_name_ == hash_code && child->IsName(child_name)) + { + RemoveChild(child); + } + } +} + +void Actor::RemoveAllChildren() +{ + children_.clear(); +} + +void Actor::SetResponsible(bool enable) +{ + responsible_ = enable; +} + +bool Actor::ContainsPoint(const Point& point) const +{ + if (size_.x == 0.f || size_.y == 0.f) + return false; + + Point local = GetTransformInverseMatrix().Transform(point); + return GetBounds().ContainsPoint(local); +} + +} // namespace kiwano diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index d3925ebb..f8fa0f2a 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -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,674 +19,674 @@ // THE SOFTWARE. #pragma once -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include namespace kiwano { - class Stage; - class Director; - class RenderContext; - - KGE_DECLARE_SMART_PTR(Actor); - - /** - * \~chinese - * \defgroup Actors 基础角色 - */ - - /** - * \addtogroup Actors - * @{ - */ - - /** - * \~chinese - * @brief 角色 - * @details 角色是舞台上最基本的元素,是完成渲染、更新、事件分发等功能的最小单位,也是动画、定时器、事件监听等功能的载体 - */ - class KGE_API Actor - : public virtual ObjectBase - , public TimerManager - , public ActionManager - , public EventDispatcher - , protected IntrusiveListItem - { - friend class Director; - friend class Transition; - friend IntrusiveList; - - public: - /// \~chinese - /// @brief 子成员列表 - using Children = IntrusiveList; - - /// \~chinese - /// @brief 角色更新回调函数 - using UpdateCallback = Function; - - Actor(); - - virtual ~Actor(); - - /// \~chinese - /// @brief 更新角色 - /// @details 每帧画面刷新前调用该函数,重载该函数以实现角色的更新处理 - /// @param dt 距上一次更新的时间间隔 - virtual void OnUpdate(Duration dt); - - /// \~chinese - /// @brief 渲染角色 - /// @details 每帧画面刷新时调用该函数,默认不进行渲染,重载该函数以实现具体渲染过程 - /// @param ctx 渲染上下文 - virtual void OnRender(RenderContext& ctx); - - /// \~chinese - /// @brief 获取显示状态 - bool IsVisible() const; - - /// \~chinese - /// @brief 获取响应状态 - bool IsResponsible() const; - - /// \~chinese - /// @brief 是否启用级联透明度 - bool IsCascadeOpacityEnabled() const; - - /// \~chinese - /// @brief 获取名称的 Hash 值 - size_t GetHashName() const; - - /// \~chinese - /// @brief 获取 Z 轴顺序 - int GetZOrder() const; - - /// \~chinese - /// @brief 获取坐标 - Point const& GetPosition() const; - - /// \~chinese - /// @brief 获取 x 坐标 - float GetPositionX() const; - - /// \~chinese - /// @brief 获取 y 坐标 - float GetPositionY() const; - - /// \~chinese - /// @brief 获取宽度 - float GetWidth() const; - - /// \~chinese - /// @brief 获取高度 - float GetHeight() const; - - /// \~chinese - /// @brief 获取大小 - Size const& GetSize() const; - - /// \~chinese - /// @brief 获取缩放后的宽度 - float GetScaledWidth() const; - - /// \~chinese - /// @brief 获取缩放后的高度 - float GetScaledHeight() const; - - /// \~chinese - /// @brief 获取缩放后的大小 - Size GetScaledSize() const; - - /// \~chinese - /// @brief 获取锚点 - Point const& GetAnchor() const; - - /// \~chinese - /// @brief 获取 x 方向锚点 - float GetAnchorX() const; - - /// \~chinese - /// @brief 获取 y 方向锚点 - float GetAnchorY() const; - - /// \~chinese - /// @brief 获取透明度 - float GetOpacity() const; +class Stage; +class Director; +class RenderContext; + +KGE_DECLARE_SMART_PTR(Actor); + +/** + * \~chinese + * \defgroup Actors 基础角色 + */ + +/** + * \addtogroup Actors + * @{ + */ + +/** + * \~chinese + * @brief 角色 + * @details + * 角色是舞台上最基本的元素,是完成渲染、更新、事件分发等功能的最小单位,也是动画、定时器、事件监听等功能的载体 + */ +class KGE_API Actor + : public virtual ObjectBase + , public TimerManager + , public ActionManager + , public EventDispatcher + , protected IntrusiveListItem +{ + friend class Director; + friend class Transition; + friend IntrusiveList; + +public: + /// \~chinese + /// @brief 子成员列表 + using Children = IntrusiveList; + + /// \~chinese + /// @brief 角色更新回调函数 + using UpdateCallback = Function; + + Actor(); + + virtual ~Actor(); + + /// \~chinese + /// @brief 更新角色 + /// @details 每帧画面刷新前调用该函数,重载该函数以实现角色的更新处理 + /// @param dt 距上一次更新的时间间隔 + virtual void OnUpdate(Duration dt); + + /// \~chinese + /// @brief 渲染角色 + /// @details + /// 每帧画面刷新时调用该函数,默认不进行渲染,重载该函数以实现具体渲染过程 + /// @param ctx 渲染上下文 + virtual void OnRender(RenderContext& ctx); + + /// \~chinese + /// @brief 获取显示状态 + bool IsVisible() const; + + /// \~chinese + /// @brief 获取响应状态 + bool IsResponsible() const; + + /// \~chinese + /// @brief 是否启用级联透明度 + bool IsCascadeOpacityEnabled() const; + + /// \~chinese + /// @brief 获取名称的 Hash 值 + size_t GetHashName() const; + + /// \~chinese + /// @brief 获取 Z 轴顺序 + int GetZOrder() const; + + /// \~chinese + /// @brief 获取坐标 + Point const& GetPosition() const; + + /// \~chinese + /// @brief 获取 x 坐标 + float GetPositionX() const; + + /// \~chinese + /// @brief 获取 y 坐标 + float GetPositionY() const; + + /// \~chinese + /// @brief 获取宽度 + float GetWidth() const; + + /// \~chinese + /// @brief 获取高度 + float GetHeight() const; + + /// \~chinese + /// @brief 获取大小 + Size const& GetSize() const; + + /// \~chinese + /// @brief 获取缩放后的宽度 + float GetScaledWidth() const; + + /// \~chinese + /// @brief 获取缩放后的高度 + float GetScaledHeight() const; + + /// \~chinese + /// @brief 获取缩放后的大小 + Size GetScaledSize() const; + + /// \~chinese + /// @brief 获取锚点 + Point const& GetAnchor() const; + + /// \~chinese + /// @brief 获取 x 方向锚点 + float GetAnchorX() const; + + /// \~chinese + /// @brief 获取 y 方向锚点 + float GetAnchorY() const; + + /// \~chinese + /// @brief 获取透明度 + float GetOpacity() const; - /// \~chinese - /// @brief 获取显示透明度 - float GetDisplayedOpacity() const; + /// \~chinese + /// @brief 获取显示透明度 + float GetDisplayedOpacity() const; - /// \~chinese - /// @brief 获取旋转角度 - float GetRotation() const; + /// \~chinese + /// @brief 获取旋转角度 + float GetRotation() const; - /// \~chinese - /// @brief 获取缩放比例 - Point const& GetScale() const; + /// \~chinese + /// @brief 获取缩放比例 + Point const& GetScale() const; - /// \~chinese - /// @brief 获取横向缩放比例 - float GetScaleX() const; + /// \~chinese + /// @brief 获取横向缩放比例 + float GetScaleX() const; + + /// \~chinese + /// @brief 获取纵向缩放比例 + float GetScaleY() const; - /// \~chinese - /// @brief 获取纵向缩放比例 - float GetScaleY() const; + /// \~chinese + /// @brief 获取错切角度 + Point const& GetSkew() const; - /// \~chinese - /// @brief 获取错切角度 - Point const& GetSkew() const; + /// \~chinese + /// @brief 获取横向错切角度 + float GetSkewX() const; - /// \~chinese - /// @brief 获取横向错切角度 - float GetSkewX() const; + /// \~chinese + /// @brief 获取纵向错切角度 + float GetSkewY() const; - /// \~chinese - /// @brief 获取纵向错切角度 - float GetSkewY() const; + /// \~chinese + /// @brief 获取变换 + Transform GetTransform() const; - /// \~chinese - /// @brief 获取变换 - Transform GetTransform() const; + /// \~chinese + /// @brief 获取父角色 + Actor* GetParent() const; - /// \~chinese - /// @brief 获取父角色 - Actor* GetParent() const; + /// \~chinese + /// @brief 获取所在舞台 + Stage* GetStage() const; - /// \~chinese - /// @brief 获取所在舞台 - Stage* GetStage() const; + /// \~chinese + /// @brief 获取边框 + virtual Rect GetBounds() const; - /// \~chinese - /// @brief 获取边框 - virtual Rect GetBounds() const; + /// \~chinese + /// @brief 获取外切包围盒 + virtual Rect GetBoundingBox() const; - /// \~chinese - /// @brief 获取外切包围盒 - virtual Rect GetBoundingBox() const; + /// \~chinese + /// @brief 获取二维变换矩阵 + Matrix3x2 const& GetTransformMatrix() const; - /// \~chinese - /// @brief 获取二维变换矩阵 - Matrix3x2 const& GetTransformMatrix() const; + /// \~chinese + /// @brief 获取二维变换的逆矩阵 + Matrix3x2 const& GetTransformInverseMatrix() const; - /// \~chinese - /// @brief 获取二维变换的逆矩阵 - Matrix3x2 const& GetTransformInverseMatrix() const; + /// \~chinese + /// @brief 设置角色是否可见 + void SetVisible(bool val); - /// \~chinese - /// @brief 设置角色是否可见 - void SetVisible(bool val); + /// \~chinese + /// @brief 设置名称 + void SetName(String const& name); - /// \~chinese - /// @brief 设置名称 - void SetName(String const& name); + /// \~chinese + /// @brief 设置坐标 + virtual void SetPosition(Point const& point); - /// \~chinese - /// @brief 设置坐标 - virtual void SetPosition(Point const& point); + /// \~chinese + /// @brief 设置坐标 + void SetPosition(float x, float y); - /// \~chinese - /// @brief 设置坐标 - void SetPosition(float x, float y); + /// \~chinese + /// @brief 设置横坐标 + void SetPositionX(float x); - /// \~chinese - /// @brief 设置横坐标 - void SetPositionX(float x); + /// \~chinese + /// @brief 设置纵坐标 + void SetPositionY(float y); - /// \~chinese - /// @brief 设置纵坐标 - void SetPositionY(float y); + /// \~chinese + /// @brief 移动坐标 + void Move(Vec2 const& v); - /// \~chinese - /// @brief 移动坐标 - void Move(Vec2 const& v); + /// \~chinese + /// @brief 移动坐标 + void Move(float vx, float vy); - /// \~chinese - /// @brief 移动坐标 - void Move(float vx, float vy); + /// \~chinese + /// @brief 设置缩放比例,默认为 (1.0, 1.0) + virtual void SetScale(Vec2 const& scale); - /// \~chinese - /// @brief 设置缩放比例,默认为 (1.0, 1.0) - virtual void SetScale(Vec2 const& scale); + /// \~chinese + /// @brief 设置缩放比例,默认为 (1.0, 1.0) + void SetScale(float scalex, float scaley); - /// \~chinese - /// @brief 设置缩放比例,默认为 (1.0, 1.0) - void SetScale(float scalex, float scaley); + /// \~chinese + /// @brief 设置错切角度,默认为 (0, 0) + virtual void SetSkew(Vec2 const& skew); - /// \~chinese - /// @brief 设置错切角度,默认为 (0, 0) - virtual void SetSkew(Vec2 const& skew); + /// \~chinese + /// @brief 设置错切角度,默认为 (0, 0) + void SetSkew(float skewx, float skewy); - /// \~chinese - /// @brief 设置错切角度,默认为 (0, 0) - void SetSkew(float skewx, float skewy); + /// \~chinese + /// @brief 设置旋转角度,默认为 0 + virtual void SetRotation(float rotation); - /// \~chinese - /// @brief 设置旋转角度,默认为 0 - virtual void SetRotation(float rotation); + /// \~chinese + /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1] + virtual void SetAnchor(Vec2 const& anchor); - /// \~chinese - /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1] - virtual void SetAnchor(Vec2 const& anchor); + /// \~chinese + /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1] + void SetAnchor(float anchorx, float anchory); - /// \~chinese - /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1] - void SetAnchor(float anchorx, float anchory); + /// \~chinese + /// @brief 修改宽度 + virtual void SetWidth(float width); - /// \~chinese - /// @brief 修改宽度 - virtual void SetWidth(float width); + /// \~chinese + /// @brief 修改高度 + virtual void SetHeight(float height); - /// \~chinese - /// @brief 修改高度 - virtual void SetHeight(float height); + /// \~chinese + /// @brief 修改大小 + virtual void SetSize(Size const& size); - /// \~chinese - /// @brief 修改大小 - virtual void SetSize(Size const& size); + /// \~chinese + /// @brief 修改大小 + void SetSize(float width, float height); - /// \~chinese - /// @brief 修改大小 - void SetSize(float width, float height); + /// \~chinese + /// @brief 设置透明度,默认为 1.0, 范围 [0, 1] + virtual void SetOpacity(float opacity); - /// \~chinese - /// @brief 设置透明度,默认为 1.0, 范围 [0, 1] - virtual void SetOpacity(float opacity); + /// \~chinese + /// @brief 启用或禁用级联透明度 + void SetCascadeOpacityEnabled(bool enabled); - /// \~chinese - /// @brief 启用或禁用级联透明度 - void SetCascadeOpacityEnabled(bool enabled); + /// \~chinese + /// @brief 设置二维仿射变换 + void SetTransform(Transform const& transform); - /// \~chinese - /// @brief 设置二维仿射变换 - void SetTransform(Transform const& transform); - - /// \~chinese - /// @brief 设置 Z 轴顺序,默认为 0 - void SetZOrder(int zorder); - - /// \~chinese - /// @brief 设置角色是否可响应,默认为 false - /// @details 可响应的角色会收到鼠标的 Hover | Out | Click 消息 - void SetResponsible(bool enable); - - /// \~chinese - /// @brief 添加子角色 - void AddChild(ActorPtr child, int zorder = 0); - - /// \~chinese - /// @brief 添加子角色 - void AddChild(Actor* child, int zorder = 0); - - /// \~chinese - /// @brief 添加多个子角色 - void AddChildren(Vector const& children); - - /// \~chinese - /// @brief 获取名称相同的子角色 - Actor* GetChild(String const& name) const; - - /// \~chinese - /// @brief 获取所有名称相同的子角色 - Vector GetChildren(String const& name) const; - - /// \~chinese - /// @brief 获取全部子角色 - Children& GetAllChildren(); - - /// \~chinese - /// @brief 获取全部子角色 - Children const& GetAllChildren() const; - - /// \~chinese - /// @brief 移除子角色 - void RemoveChild(ActorPtr child); - - /// \~chinese - /// @brief 移除子角色 - void RemoveChild(Actor* child); - - /// \~chinese - /// @brief 移除所有名称相同的子角色 - void RemoveChildren(String const& child_name); - - /// \~chinese - /// @brief 移除所有角色 - void RemoveAllChildren(); - - /// \~chinese - /// @brief 从父角色移除 - void RemoveFromParent(); - - /// \~chinese - /// @brief 暂停角色更新 - void PauseUpdating(); - - /// \~chinese - /// @brief 继续角色更新 - void ResumeUpdating(); - - /// \~chinese - /// @brief 角色更新是否暂停 - bool IsUpdatePausing() const; - - /// \~chinese - /// @brief 设置更新时的回调函数 - void SetCallbackOnUpdate(UpdateCallback const& cb); - - /// \~chinese - /// @brief 获取更新时的回调函数 - UpdateCallback GetCallbackOnUpdate() const; - - /// \~chinese - /// @brief 判断点是否在角色内 - virtual bool ContainsPoint(const Point& point) const; - - /// \~chinese - /// @brief 渲染角色边界 - void ShowBorder(bool show); - - /// \~chinese - /// @brief 分发事件 - /// @param evt 事件 - /// @return 是否继续分发该事件 - virtual bool DispatchEvent(Event* evt); - - /// \~chinese - /// @brief 设置默认锚点 - static void SetDefaultAnchor(float anchor_x, float anchor_y); - - protected: - /// \~chinese - /// @brief 更新自身和所有子角色 - virtual void Update(Duration dt); - - /// \~chinese - /// @brief 渲染自身和所有子角色 - virtual void Render(RenderContext& ctx); - - /// \~chinese - /// @brief 绘制自身和所有子角色的边界 - virtual void RenderBorder(RenderContext& ctx); - - /// \~chinese - /// @brief 检查是否在渲染上下文的视区内 - virtual bool CheckVisibility(RenderContext& ctx) const; - - /// \~chinese - /// @brief 渲染前初始化渲染上下文状态,仅当 CheckVisibility 返回真时调用该函数 - virtual void PrepareToRender(RenderContext& ctx); - - /// \~chinese - /// @brief 更新自己的二维变换,并通知所有子角色 - void UpdateTransform() const; - - /// \~chinese - /// @brief 更新自己和所有子角色的透明度 - void UpdateOpacity(); - - /// \~chinese - /// @brief 将所有子角色按Z轴顺序排序 - void Reorder(); - - /// \~chinese - /// @brief 设置节点所在舞台 - void SetStage(Stage* stage); - - /// \~chinese - /// @brief 处理事件 - void HandleEvent(Event* evt); - - private: - bool visible_; - bool update_pausing_; - bool cascade_opacity_; - bool show_border_; - bool hover_; - bool pressed_; - bool responsible_; - int z_order_; - float opacity_; - float displayed_opacity_; - Actor* parent_; - Stage* stage_; - size_t hash_name_; - Point anchor_; - Size size_; - Children children_; - UpdateCallback cb_update_; - Transform transform_; - - bool is_fast_transform_; - mutable bool visible_in_rt_; - mutable bool dirty_visibility_; - mutable bool dirty_transform_; - mutable bool dirty_transform_inverse_; - mutable Matrix3x2 transform_matrix_; - mutable Matrix3x2 transform_matrix_inverse_; - }; - - /** @} */ - - - inline void Actor::OnUpdate(Duration dt) - { - KGE_NOT_USED(dt); - } - - inline void Actor::OnRender(RenderContext& ctx) - { - KGE_NOT_USED(ctx); - } - - inline bool Actor::IsVisible() const - { - return visible_; - } - - inline bool Actor::IsResponsible() const - { - return responsible_; - } - - inline bool Actor::IsCascadeOpacityEnabled() const - { - return cascade_opacity_; - } - - inline size_t Actor::GetHashName() const - { - return hash_name_; - } - - inline int Actor::GetZOrder() const - { - return z_order_; - } - - inline Point const& Actor::GetPosition() const - { - return transform_.position; - } - - inline float Actor::GetPositionX() const - { - return GetPosition().x; - } - - inline float Actor::GetPositionY() const - { - return GetPosition().y; - } - - inline Point const& Actor::GetScale() const - { - return transform_.scale; - } - - inline float Actor::GetScaleX() const - { - return GetScale().x; - } - - inline float Actor::GetScaleY() const - { - return GetScale().y; - } - - inline Point const& Actor::GetSkew() const - { - return transform_.skew; - } - - inline float Actor::GetSkewX() const - { - return GetSkew().x; - } - - inline float Actor::GetSkewY() const - { - return GetSkew().y; - } - - inline float Actor::GetRotation() const - { - return transform_.rotation; - } - - inline float Actor::GetWidth() const - { - return GetSize().x; - } - - inline float Actor::GetHeight() const - { - return GetSize().y; - } - - inline Size const& Actor::GetSize() const - { - return size_; - } - - inline float Actor::GetScaledWidth() const - { - return GetWidth() * GetScaleX(); - } - - inline float Actor::GetScaledHeight() const - { - return GetHeight() * GetScaleY(); - } - - inline Size Actor::GetScaledSize() const - { - return Size{ GetScaledWidth(), GetScaledHeight() }; - } - - inline Point const& Actor::GetAnchor() const - { - return anchor_; - } - - inline float Actor::GetAnchorX() const - { - return GetAnchor().x; - } - - inline float Actor::GetAnchorY() const - { - return GetAnchor().y; - } - - inline float Actor::GetOpacity() const - { - return opacity_; - } - - inline float Actor::GetDisplayedOpacity() const - { - return displayed_opacity_; - } - - inline Transform Actor::GetTransform() const - { - return transform_; - } - - inline Actor* Actor::GetParent() const - { - return parent_; - } - - inline Stage* Actor::GetStage() const - { - return stage_; - } - - inline void Actor::PauseUpdating() - { - update_pausing_ = true; - } - - inline void Actor::ResumeUpdating() - { - update_pausing_ = false; - } - - inline bool Actor::IsUpdatePausing() const - { - return update_pausing_; - } - - inline void Actor::SetCallbackOnUpdate(UpdateCallback const& cb) - { - cb_update_ = cb; - } - - inline Actor::UpdateCallback Actor::GetCallbackOnUpdate() const - { - return cb_update_; - } - - inline void Actor::ShowBorder(bool show) - { - show_border_ = show; - } - - inline void Actor::SetPosition(float x, float y) - { - SetPosition(Point{ x, y }); - } - - inline void Actor::Move(float vx, float vy) - { - Move(Vec2{ vx, vy }); - } - - inline void Actor::SetScale(float scalex, float scaley) - { - SetScale(Vec2{ scalex, scaley }); - } - - inline void Actor::SetAnchor(float anchorx, float anchory) - { - SetAnchor(Vec2{ anchorx, anchory }); - } - - inline void Actor::SetSize(float width, float height) - { - SetSize(Size{ width, height }); - } - - inline void Actor::SetSkew(float skewx, float skewy) - { - SetSkew(Vec2{ skewx, skewy }); - } + /// \~chinese + /// @brief 设置 Z 轴顺序,默认为 0 + void SetZOrder(int zorder); + /// \~chinese + /// @brief 设置角色是否可响应,默认为 false + /// @details 可响应的角色会收到鼠标的 Hover | Out | Click 消息 + void SetResponsible(bool enable); + + /// \~chinese + /// @brief 添加子角色 + void AddChild(ActorPtr child, int zorder = 0); + + /// \~chinese + /// @brief 添加子角色 + void AddChild(Actor* child, int zorder = 0); + + /// \~chinese + /// @brief 添加多个子角色 + void AddChildren(Vector const& children); + + /// \~chinese + /// @brief 获取名称相同的子角色 + Actor* GetChild(String const& name) const; + + /// \~chinese + /// @brief 获取所有名称相同的子角色 + Vector GetChildren(String const& name) const; + + /// \~chinese + /// @brief 获取全部子角色 + Children& GetAllChildren(); + + /// \~chinese + /// @brief 获取全部子角色 + Children const& GetAllChildren() const; + + /// \~chinese + /// @brief 移除子角色 + void RemoveChild(ActorPtr child); + + /// \~chinese + /// @brief 移除子角色 + void RemoveChild(Actor* child); + + /// \~chinese + /// @brief 移除所有名称相同的子角色 + void RemoveChildren(String const& child_name); + + /// \~chinese + /// @brief 移除所有角色 + void RemoveAllChildren(); + + /// \~chinese + /// @brief 从父角色移除 + void RemoveFromParent(); + + /// \~chinese + /// @brief 暂停角色更新 + void PauseUpdating(); + + /// \~chinese + /// @brief 继续角色更新 + void ResumeUpdating(); + + /// \~chinese + /// @brief 角色更新是否暂停 + bool IsUpdatePausing() const; + + /// \~chinese + /// @brief 设置更新时的回调函数 + void SetCallbackOnUpdate(UpdateCallback const& cb); + + /// \~chinese + /// @brief 获取更新时的回调函数 + UpdateCallback GetCallbackOnUpdate() const; + + /// \~chinese + /// @brief 判断点是否在角色内 + virtual bool ContainsPoint(const Point& point) const; + + /// \~chinese + /// @brief 渲染角色边界 + void ShowBorder(bool show); + + /// \~chinese + /// @brief 分发事件 + /// @param evt 事件 + /// @return 是否继续分发该事件 + virtual bool DispatchEvent(Event* evt); + + /// \~chinese + /// @brief 设置默认锚点 + static void SetDefaultAnchor(float anchor_x, float anchor_y); + +protected: + /// \~chinese + /// @brief 更新自身和所有子角色 + virtual void Update(Duration dt); + + /// \~chinese + /// @brief 渲染自身和所有子角色 + virtual void Render(RenderContext& ctx); + + /// \~chinese + /// @brief 绘制自身和所有子角色的边界 + virtual void RenderBorder(RenderContext& ctx); + + /// \~chinese + /// @brief 检查是否在渲染上下文的视区内 + virtual bool CheckVisibility(RenderContext& ctx) const; + + /// \~chinese + /// @brief 渲染前初始化渲染上下文状态,仅当 CheckVisibility 返回真时调用该函数 + virtual void PrepareToRender(RenderContext& ctx); + + /// \~chinese + /// @brief 更新自己的二维变换,并通知所有子角色 + void UpdateTransform() const; + + /// \~chinese + /// @brief 更新自己和所有子角色的透明度 + void UpdateOpacity(); + + /// \~chinese + /// @brief 将所有子角色按Z轴顺序排序 + void Reorder(); + + /// \~chinese + /// @brief 设置节点所在舞台 + void SetStage(Stage* stage); + + /// \~chinese + /// @brief 处理事件 + void HandleEvent(Event* evt); + +private: + bool visible_; + bool update_pausing_; + bool cascade_opacity_; + bool show_border_; + bool hover_; + bool pressed_; + bool responsible_; + int z_order_; + float opacity_; + float displayed_opacity_; + Actor* parent_; + Stage* stage_; + size_t hash_name_; + Point anchor_; + Size size_; + Children children_; + UpdateCallback cb_update_; + Transform transform_; + + bool is_fast_transform_; + mutable bool visible_in_rt_; + mutable bool dirty_visibility_; + mutable bool dirty_transform_; + mutable bool dirty_transform_inverse_; + mutable Matrix3x2 transform_matrix_; + mutable Matrix3x2 transform_matrix_inverse_; +}; + +/** @} */ + +inline void Actor::OnUpdate(Duration dt) +{ + KGE_NOT_USED(dt); } + +inline void Actor::OnRender(RenderContext& ctx) +{ + KGE_NOT_USED(ctx); +} + +inline bool Actor::IsVisible() const +{ + return visible_; +} + +inline bool Actor::IsResponsible() const +{ + return responsible_; +} + +inline bool Actor::IsCascadeOpacityEnabled() const +{ + return cascade_opacity_; +} + +inline size_t Actor::GetHashName() const +{ + return hash_name_; +} + +inline int Actor::GetZOrder() const +{ + return z_order_; +} + +inline Point const& Actor::GetPosition() const +{ + return transform_.position; +} + +inline float Actor::GetPositionX() const +{ + return GetPosition().x; +} + +inline float Actor::GetPositionY() const +{ + return GetPosition().y; +} + +inline Point const& Actor::GetScale() const +{ + return transform_.scale; +} + +inline float Actor::GetScaleX() const +{ + return GetScale().x; +} + +inline float Actor::GetScaleY() const +{ + return GetScale().y; +} + +inline Point const& Actor::GetSkew() const +{ + return transform_.skew; +} + +inline float Actor::GetSkewX() const +{ + return GetSkew().x; +} + +inline float Actor::GetSkewY() const +{ + return GetSkew().y; +} + +inline float Actor::GetRotation() const +{ + return transform_.rotation; +} + +inline float Actor::GetWidth() const +{ + return GetSize().x; +} + +inline float Actor::GetHeight() const +{ + return GetSize().y; +} + +inline Size const& Actor::GetSize() const +{ + return size_; +} + +inline float Actor::GetScaledWidth() const +{ + return GetWidth() * GetScaleX(); +} + +inline float Actor::GetScaledHeight() const +{ + return GetHeight() * GetScaleY(); +} + +inline Size Actor::GetScaledSize() const +{ + return Size{ GetScaledWidth(), GetScaledHeight() }; +} + +inline Point const& Actor::GetAnchor() const +{ + return anchor_; +} + +inline float Actor::GetAnchorX() const +{ + return GetAnchor().x; +} + +inline float Actor::GetAnchorY() const +{ + return GetAnchor().y; +} + +inline float Actor::GetOpacity() const +{ + return opacity_; +} + +inline float Actor::GetDisplayedOpacity() const +{ + return displayed_opacity_; +} + +inline Transform Actor::GetTransform() const +{ + return transform_; +} + +inline Actor* Actor::GetParent() const +{ + return parent_; +} + +inline Stage* Actor::GetStage() const +{ + return stage_; +} + +inline void Actor::PauseUpdating() +{ + update_pausing_ = true; +} + +inline void Actor::ResumeUpdating() +{ + update_pausing_ = false; +} + +inline bool Actor::IsUpdatePausing() const +{ + return update_pausing_; +} + +inline void Actor::SetCallbackOnUpdate(UpdateCallback const& cb) +{ + cb_update_ = cb; +} + +inline Actor::UpdateCallback Actor::GetCallbackOnUpdate() const +{ + return cb_update_; +} + +inline void Actor::ShowBorder(bool show) +{ + show_border_ = show; +} + +inline void Actor::SetPosition(float x, float y) +{ + SetPosition(Point{ x, y }); +} + +inline void Actor::Move(float vx, float vy) +{ + Move(Vec2{ vx, vy }); +} + +inline void Actor::SetScale(float scalex, float scaley) +{ + SetScale(Vec2{ scalex, scaley }); +} + +inline void Actor::SetAnchor(float anchorx, float anchory) +{ + SetAnchor(Vec2{ anchorx, anchory }); +} + +inline void Actor::SetSize(float width, float height) +{ + SetSize(Size{ width, height }); +} + +inline void Actor::SetSkew(float skewx, float skewy) +{ + SetSkew(Vec2{ skewx, skewy }); +} +} // namespace kiwano diff --git a/src/kiwano/2d/Button.cpp b/src/kiwano/2d/Button.cpp index 1e2d04c6..7206af50 100644 --- a/src/kiwano/2d/Button.cpp +++ b/src/kiwano/2d/Button.cpp @@ -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()) - { - SetStatus(Status::Hover); - } - else if (evt->IsType()) - { - SetStatus(Status::Normal); - } - else if (evt->IsType() && status_ == Status::Hover) - { - SetStatus(Status::Pressed); - } - else if (evt->IsType() && status_ == Status::Pressed) - { - SetStatus(Status::Hover); - } - else if (evt->IsType()) - { - 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(handler); - AddListener(handler); - AddListener(handler); - AddListener(handler); - AddListener(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(handler); - AddListener(handler); - AddListener(handler); - AddListener(handler); - AddListener(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()) + { + SetStatus(Status::Hover); + } + else if (evt->IsType()) + { + SetStatus(Status::Normal); + } + else if (evt->IsType() && status_ == Status::Hover) + { + SetStatus(Status::Pressed); + } + else if (evt->IsType() && status_ == Status::Pressed) + { + SetStatus(Status::Hover); + } + else if (evt->IsType()) + { + 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(handler); + AddListener(handler); + AddListener(handler); + AddListener(handler); + AddListener(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(handler); + AddListener(handler); + AddListener(handler); + AddListener(handler); + AddListener(handler); +} + +} // namespace kiwano diff --git a/src/kiwano/2d/Button.h b/src/kiwano/2d/Button.h index e8fc1af2..5947afe8 100644 --- a/src/kiwano/2d/Button.h +++ b/src/kiwano/2d/Button.h @@ -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; +/** + * \~chinese + * @brief 按钮 + */ +class KGE_API Button : public virtual ObjectBase +{ +public: + /// \~chinese + /// @brief 按钮回调函数 + using Callback = Function; - 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 diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index 4d52d390..e2f1fc44 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -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 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 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 diff --git a/src/kiwano/2d/Canvas.h b/src/kiwano/2d/Canvas.h index a5774da1..064b4b3d 100644 --- a/src/kiwano/2d/Canvas.h +++ b/src/kiwano/2d/Canvas.h @@ -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 -#include #include +#include 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 const& points); + /// \~chinese + /// @brief 添加多条线段 + /// @param points 端点集合 + void AddLines(Vector 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 diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index e67dc8a2..8e40b65a 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -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 -#include #include +#include #include #pragma comment(lib, "psapi.lib") namespace kiwano { - namespace - { - class comma_numpunct : public std::numpunct - { - private: - virtual wchar_t do_thousands_sep() const override - { - return L','; - } +namespace +{ +class comma_numpunct : public std::numpunct +{ +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([=](Event*) { SetOpacity(0.4f); }); - AddListener([=](Event*) { SetOpacity(1.f); }); - } + AddListener([=](Event*) { SetOpacity(0.4f); }); + AddListener([=](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 diff --git a/src/kiwano/2d/DebugActor.h b/src/kiwano/2d/DebugActor.h index a681ee50..e8d33e2e 100644 --- a/src/kiwano/2d/DebugActor.h +++ b/src/kiwano/2d/DebugActor.h @@ -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