commit
b4f1f0f566
|
|
@ -14,6 +14,7 @@ Release/
|
|||
.vs
|
||||
.idea
|
||||
._Kiwano.sln
|
||||
.vscode
|
||||
|
||||
# vs2010
|
||||
ipch/
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/src",
|
||||
"${workspaceFolder}/src/3rd-party"
|
||||
],
|
||||
"defines": [
|
||||
"TARGET_OS_MAC"
|
||||
],
|
||||
"macFrameworkPath": [
|
||||
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
|
||||
],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "clang-x64"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/src",
|
||||
"${workspaceFolder}/src/3rd-party"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"files.autoGuessEncoding": true,
|
||||
"files.encoding": "gb2312"
|
||||
}
|
||||
|
|
@ -82,6 +82,7 @@
|
|||
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\Input.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\Keys.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\NativeObject.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\Runner.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
|
||||
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" />
|
||||
|
|
@ -96,12 +97,10 @@
|
|||
<ClInclude Include="..\..\src\kiwano\render\DirectX\D3DDeviceResourcesBase.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\FontCollectionLoader.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\helper.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\NativePtr.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\RenderContextImpl.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\RendererImpl.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextRenderer.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\Font.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\NativeObject.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\Shape.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\ShapeMaker.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\render\GifImage.h" />
|
||||
|
|
@ -193,7 +192,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano\render\DirectX\RendererImpl.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\render\DirectX\TextRenderer.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\render\Font.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\render\NativeObject.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\render\Shape.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\render\ShapeMaker.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\render\GifImage.cpp" />
|
||||
|
|
|
|||
|
|
@ -222,12 +222,6 @@
|
|||
<ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\render\NativeObject.h">
|
||||
<Filter>render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\render\DirectX\NativePtr.h">
|
||||
<Filter>render\DirectX</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\render\ShapeMaker.h">
|
||||
<Filter>render</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -411,6 +405,9 @@
|
|||
<ClInclude Include="..\..\src\kiwano\render\DirectX\TextDrawingEffect.h">
|
||||
<Filter>render\DirectX</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\platform\NativeObject.hpp">
|
||||
<Filter>platform</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
||||
|
|
@ -608,9 +605,6 @@
|
|||
<ClCompile Include="..\..\src\kiwano\render\TextStyle.cpp">
|
||||
<Filter>render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\render\NativeObject.cpp">
|
||||
<Filter>render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\Duration.cpp">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
|||
|
|
@ -22,11 +22,52 @@
|
|||
#include <kiwano-audio/libraries.h>
|
||||
#include <kiwano/core/Exception.h>
|
||||
#include <kiwano/utils/Logger.h>
|
||||
#include <kiwano/platform/FileSystem.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
|
||||
class VoiceCallback : public IXAudio2VoiceCallback
|
||||
{
|
||||
public:
|
||||
SoundCallback* cb;
|
||||
|
||||
VoiceCallback(SoundCallback* cb)
|
||||
: cb(cb)
|
||||
{
|
||||
}
|
||||
|
||||
~VoiceCallback() {}
|
||||
|
||||
STDMETHOD_(void, OnBufferStart(void* pBufferContext))
|
||||
{
|
||||
cb->OnStart(nullptr);
|
||||
}
|
||||
|
||||
STDMETHOD_(void, OnLoopEnd(void* pBufferContext))
|
||||
{
|
||||
cb->OnLoopEnd(nullptr);
|
||||
}
|
||||
|
||||
STDMETHOD_(void, OnBufferEnd(void* pBufferContext))
|
||||
{
|
||||
cb->OnEnd(nullptr);
|
||||
}
|
||||
|
||||
STDMETHOD_(void, OnStreamEnd()) {}
|
||||
|
||||
STDMETHOD_(void, OnVoiceProcessingPassEnd()) {}
|
||||
|
||||
STDMETHOD_(void, OnVoiceProcessingPassStart(UINT32 SamplesRequired)) {}
|
||||
|
||||
STDMETHOD_(void, OnVoiceError(void* pBufferContext, HRESULT Error))
|
||||
{
|
||||
KGE_ERRORF("Voice error with HRESULT of %08X", Error);
|
||||
}
|
||||
};
|
||||
|
||||
AudioModule::AudioModule()
|
||||
: x_audio2_(nullptr)
|
||||
, mastering_voice_(nullptr)
|
||||
|
|
@ -58,6 +99,8 @@ void AudioModule::DestroyModule()
|
|||
{
|
||||
KGE_DEBUG_LOGF("Destroying audio resources");
|
||||
|
||||
TranscoderCache::GetInstance().Clear();
|
||||
|
||||
if (mastering_voice_)
|
||||
{
|
||||
mastering_voice_->DestroyVoice();
|
||||
|
|
@ -73,31 +116,60 @@ void AudioModule::DestroyModule()
|
|||
dlls::MediaFoundation::Get().MFShutdown();
|
||||
}
|
||||
|
||||
bool AudioModule::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
||||
TranscoderPtr AudioModule::CreateTranscoder(const String& file_path)
|
||||
{
|
||||
if (!FileSystem::GetInstance().IsFileExists(file_path))
|
||||
{
|
||||
KGE_WARNF("Media file '%s' not found", file_path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
|
||||
|
||||
auto ptr = MakePtr<Transcoder>();
|
||||
HRESULT hr = ptr->LoadMediaFile(full_path);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERRORF("Load media file failed with HRESULT of %08X", hr);
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
TranscoderPtr AudioModule::CreateTranscoder(const Resource& res)
|
||||
{
|
||||
auto ptr = MakePtr<Transcoder>();
|
||||
HRESULT hr = ptr->LoadMediaResource(res);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERRORF("Load media resource failed with HRESULT of %08X", hr);
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool AudioModule::CreateSound(Sound& sound, TranscoderPtr transcoder)
|
||||
{
|
||||
KGE_ASSERT(x_audio2_ && "AudioModule hasn't been initialized!");
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
auto buffer = transcoder->GetBuffer();
|
||||
if (buffer.format == nullptr)
|
||||
hr = E_INVALIDARG;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto chain = sound.GetCallbackChain();
|
||||
chain->SetNative(VoiceCallback{ chain.Get() });
|
||||
auto callback = const_cast<VoiceCallback*>(chain->GetNative().CastPtr<VoiceCallback>());
|
||||
|
||||
IXAudio2SourceVoice* voice = nullptr;
|
||||
|
||||
hr = x_audio2_->CreateSourceVoice(&voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
|
||||
hr = x_audio2_->CreateSourceVoice(&voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO, callback);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IXAudio2SourceVoice* old = sound.GetXAudio2Voice();
|
||||
if (old)
|
||||
{
|
||||
old->DestroyVoice();
|
||||
old = nullptr;
|
||||
}
|
||||
|
||||
sound.SetXAudio2Voice(voice);
|
||||
sound.Close();
|
||||
sound.SetNative(voice);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +184,6 @@ bool AudioModule::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
|||
void AudioModule::Open()
|
||||
{
|
||||
KGE_ASSERT(x_audio2_ && "AudioModule hasn't been initialized!");
|
||||
|
||||
if (x_audio2_)
|
||||
x_audio2_->StartEngine();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,16 @@ public:
|
|||
void Close();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 从解码器数据缓冲中创建音频对象
|
||||
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
|
||||
/// @brief 创建音频解码器
|
||||
TranscoderPtr CreateTranscoder(const String& file_path);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建音频解码器
|
||||
TranscoderPtr CreateTranscoder(const Resource& res);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建音频
|
||||
bool CreateSound(Sound& sound, TranscoderPtr transcoder);
|
||||
|
||||
public:
|
||||
void SetupModule() override;
|
||||
|
|
|
|||
|
|
@ -21,12 +21,58 @@
|
|||
#include <kiwano-audio/AudioModule.h>
|
||||
#include <kiwano-audio/Sound.h>
|
||||
#include <kiwano/utils/Logger.h>
|
||||
#include <kiwano/platform/FileSystem.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
|
||||
SoundPtr Sound::Preload(const String& file_path, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||
{
|
||||
auto ptr = MakePtr<Sound>();
|
||||
for (auto& cb : callbacks)
|
||||
{
|
||||
ptr->AddCallback(cb);
|
||||
}
|
||||
|
||||
size_t hash_code = std::hash<String>{}(file_path);
|
||||
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
||||
{
|
||||
if (ptr->Load(transcoder))
|
||||
return ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ptr && ptr->Load(file_path))
|
||||
{
|
||||
TranscoderCache::GetInstance().Add(hash_code, ptr->coder_);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
SoundPtr Sound::Preload(const Resource& res, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||
{
|
||||
auto ptr = MakePtr<Sound>();
|
||||
for (auto& cb : callbacks)
|
||||
{
|
||||
ptr->AddCallback(cb);
|
||||
}
|
||||
|
||||
size_t hash_code = res.GetId();
|
||||
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
||||
{
|
||||
if (ptr->Load(transcoder))
|
||||
return ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ptr && ptr->Load(res))
|
||||
{
|
||||
TranscoderCache::GetInstance().Add(hash_code, ptr->coder_);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Sound::Sound(const String& file_path)
|
||||
: Sound()
|
||||
{
|
||||
|
|
@ -42,7 +88,7 @@ Sound::Sound(const Resource& res)
|
|||
Sound::Sound()
|
||||
: opened_(false)
|
||||
, playing_(false)
|
||||
, voice_(nullptr)
|
||||
, volume_(1.f)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -53,34 +99,17 @@ Sound::~Sound()
|
|||
|
||||
bool Sound::Load(const String& file_path)
|
||||
{
|
||||
if (!FileSystem::GetInstance().IsFileExists(file_path))
|
||||
{
|
||||
KGE_WARNF("Media file '%s' not found", file_path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opened_)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
|
||||
|
||||
HRESULT hr = transcoder_.LoadMediaFile(full_path);
|
||||
if (FAILED(hr))
|
||||
TranscoderPtr transcoder = AudioModule::GetInstance().CreateTranscoder(file_path);
|
||||
if (!transcoder)
|
||||
{
|
||||
KGE_ERRORF("Load media file failed with HRESULT of %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AudioModule::GetInstance().CreateSound(*this, transcoder_.GetBuffer()))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
opened_ = true;
|
||||
return true;
|
||||
return Load(transcoder);
|
||||
}
|
||||
|
||||
bool Sound::Load(const Resource& res)
|
||||
|
|
@ -90,26 +119,31 @@ bool Sound::Load(const Resource& res)
|
|||
Close();
|
||||
}
|
||||
|
||||
HRESULT hr = transcoder_.LoadMediaResource(res);
|
||||
if (FAILED(hr))
|
||||
TranscoderPtr transcoder = AudioModule::GetInstance().CreateTranscoder(res);
|
||||
if (!transcoder)
|
||||
{
|
||||
KGE_ERRORF("Load media resource failed with HRESULT of %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AudioModule::GetInstance().CreateSound(*this, transcoder_.GetBuffer()))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
opened_ = true;
|
||||
return true;
|
||||
return Load(transcoder);
|
||||
}
|
||||
|
||||
bool Sound::IsValid() const
|
||||
bool Sound::Load(TranscoderPtr transcoder)
|
||||
{
|
||||
return voice_ != nullptr;
|
||||
if (opened_)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
if (!AudioModule::GetInstance().CreateSound(*this, transcoder))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// reset volume
|
||||
ResetVolume();
|
||||
|
||||
coder_ = transcoder;
|
||||
opened_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sound::Play(int loop_count)
|
||||
|
|
@ -120,29 +154,30 @@ void Sound::Play(int loop_count)
|
|||
return;
|
||||
}
|
||||
|
||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
|
||||
// if sound stream is not empty, stop() will clear it
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
voice_->GetState(&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();
|
||||
auto buffer = coder_->GetBuffer();
|
||||
|
||||
XAUDIO2_BUFFER buffer = { 0 };
|
||||
buffer.pAudioData = wave_buffer.data;
|
||||
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
||||
buffer.AudioBytes = wave_buffer.size;
|
||||
buffer.LoopCount = static_cast<uint32_t>(loop_count);
|
||||
XAUDIO2_BUFFER xaudio2_buffer = { 0 };
|
||||
xaudio2_buffer.pAudioData = buffer.data;
|
||||
xaudio2_buffer.Flags = XAUDIO2_END_OF_STREAM;
|
||||
xaudio2_buffer.AudioBytes = buffer.size;
|
||||
xaudio2_buffer.LoopCount = static_cast<uint32_t>(loop_count);
|
||||
|
||||
HRESULT hr = voice_->SubmitSourceBuffer(&buffer);
|
||||
HRESULT hr = voice->SubmitSourceBuffer(&xaudio2_buffer);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = voice_->Start();
|
||||
hr = voice->Start();
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
|
|
@ -155,48 +190,67 @@ void Sound::Play(int loop_count)
|
|||
|
||||
void Sound::Pause()
|
||||
{
|
||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
|
||||
if (SUCCEEDED(voice_->Stop()))
|
||||
HRESULT hr = voice->Stop();
|
||||
if (SUCCEEDED(hr))
|
||||
playing_ = false;
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERRORF("Pause voice failed with HRESULT of %08X", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::Resume()
|
||||
{
|
||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
|
||||
if (SUCCEEDED(voice_->Start()))
|
||||
HRESULT hr = voice->Start();
|
||||
if (SUCCEEDED(hr))
|
||||
playing_ = true;
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERRORF("Start voice failed with HRESULT of %08X", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::Stop()
|
||||
{
|
||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
|
||||
HRESULT hr = voice_->Stop();
|
||||
HRESULT hr = voice->Stop();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = voice_->ExitLoop();
|
||||
hr = voice->ExitLoop();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = voice_->FlushSourceBuffers();
|
||||
hr = voice->FlushSourceBuffers();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
playing_ = false;
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_ERRORF("Stop voice failed with HRESULT of %08X", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::Close()
|
||||
{
|
||||
if (voice_)
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
if (voice)
|
||||
{
|
||||
voice_->Stop();
|
||||
voice_->FlushSourceBuffers();
|
||||
voice_->DestroyVoice();
|
||||
voice_ = nullptr;
|
||||
voice->Stop();
|
||||
voice->FlushSourceBuffers();
|
||||
voice->DestroyVoice();
|
||||
}
|
||||
|
||||
transcoder_.ClearBuffer();
|
||||
|
||||
coder_ = nullptr;
|
||||
opened_ = false;
|
||||
playing_ = false;
|
||||
}
|
||||
|
|
@ -205,34 +259,213 @@ bool Sound::IsPlaying() const
|
|||
{
|
||||
if (opened_)
|
||||
{
|
||||
if (!voice_)
|
||||
if (!playing_)
|
||||
return false;
|
||||
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
if (!voice)
|
||||
return false;
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
voice_->GetState(&state);
|
||||
uint32_t buffers_queued = state.BuffersQueued;
|
||||
|
||||
if (buffers_queued && playing_)
|
||||
return true;
|
||||
voice->GetState(&state);
|
||||
return !!state.BuffersQueued;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float Sound::GetVolume() const
|
||||
{
|
||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
|
||||
float volume = 0.0f;
|
||||
voice_->GetVolume(&volume);
|
||||
return volume;
|
||||
return volume_;
|
||||
}
|
||||
|
||||
void Sound::SetVolume(float volume)
|
||||
{
|
||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
if (volume_ == volume)
|
||||
{
|
||||
return;
|
||||
}
|
||||
volume_ = volume;
|
||||
|
||||
volume = std::min(std::max(volume, -224.f), 224.f);
|
||||
voice_->SetVolume(volume);
|
||||
float actual_volume = GetCallbackChain()->OnVolumeChanged(this, volume_);
|
||||
|
||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||
|
||||
actual_volume = std::min(std::max(actual_volume, -XAUDIO2_MAX_VOLUME_LEVEL), XAUDIO2_MAX_VOLUME_LEVEL);
|
||||
voice->SetVolume(actual_volume);
|
||||
}
|
||||
|
||||
void Sound::ResetVolume()
|
||||
{
|
||||
const float old_volume = volume_;
|
||||
|
||||
volume_ += 1.f;
|
||||
SetVolume(old_volume);
|
||||
}
|
||||
|
||||
SoundCallbackPtr Sound::GetCallbackChain()
|
||||
{
|
||||
class SoundCallbackChain : public SoundCallback
|
||||
{
|
||||
public:
|
||||
Sound* sound;
|
||||
|
||||
void OnStart(Sound*) override
|
||||
{
|
||||
for (auto& cb : sound->GetCallbacks())
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb->OnStart(sound);
|
||||
}
|
||||
}
|
||||
RemoveUsedCallbacks();
|
||||
}
|
||||
|
||||
void OnLoopEnd(Sound*) override
|
||||
{
|
||||
for (auto& cb : sound->GetCallbacks())
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb->OnLoopEnd(sound);
|
||||
}
|
||||
}
|
||||
RemoveUsedCallbacks();
|
||||
}
|
||||
|
||||
void OnEnd(Sound*) override
|
||||
{
|
||||
for (auto& cb : sound->GetCallbacks())
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb->OnEnd(sound);
|
||||
}
|
||||
}
|
||||
RemoveUsedCallbacks();
|
||||
}
|
||||
|
||||
float OnVolumeChanged(Sound*, float volume) override
|
||||
{
|
||||
float actual_volume = volume;
|
||||
for (auto& cb : sound->GetCallbacks())
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
actual_volume = cb->OnVolumeChanged(sound, volume);
|
||||
}
|
||||
}
|
||||
return actual_volume;
|
||||
}
|
||||
|
||||
void RemoveUsedCallbacks()
|
||||
{
|
||||
auto& cbs = sound->GetCallbacks();
|
||||
auto iter = cbs.begin();
|
||||
while (iter != cbs.end())
|
||||
{
|
||||
if (*iter == nullptr)
|
||||
{
|
||||
iter = cbs.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!callback_chain_)
|
||||
{
|
||||
auto chain = MakePtr<SoundCallbackChain>();
|
||||
chain->sound = this;
|
||||
callback_chain_ = chain;
|
||||
}
|
||||
return callback_chain_;
|
||||
}
|
||||
|
||||
SoundCallbackPtr SoundCallback::OnStart(const Function<void(Sound* sound)>& cb)
|
||||
{
|
||||
class SoundCallbackFunc : public SoundCallback
|
||||
{
|
||||
public:
|
||||
Function<void(Sound* sound)> cb;
|
||||
|
||||
void OnStart(Sound* sound) override
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb(sound);
|
||||
}
|
||||
}
|
||||
};
|
||||
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||
ptr->cb = cb;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
SoundCallbackPtr SoundCallback::OnLoopEnd(const Function<void(Sound* sound)>& cb)
|
||||
{
|
||||
class SoundCallbackFunc : public SoundCallback
|
||||
{
|
||||
public:
|
||||
Function<void(Sound* sound)> cb;
|
||||
|
||||
void OnLoopEnd(Sound* sound) override
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb(sound);
|
||||
}
|
||||
}
|
||||
};
|
||||
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||
ptr->cb = cb;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
SoundCallbackPtr SoundCallback::OnEnd(const Function<void(Sound* sound)>& cb)
|
||||
{
|
||||
class SoundCallbackFunc : public SoundCallback
|
||||
{
|
||||
public:
|
||||
Function<void(Sound* sound)> cb;
|
||||
|
||||
void OnEnd(Sound* sound) override
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb(sound);
|
||||
}
|
||||
}
|
||||
};
|
||||
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||
ptr->cb = cb;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
SoundCallbackPtr SoundCallback::OnVolumeChanged(const Function<float(Sound* sound, float volume)>& cb)
|
||||
{
|
||||
class SoundCallbackFunc : public SoundCallback
|
||||
{
|
||||
public:
|
||||
Function<float(Sound* sound, float volume)> cb;
|
||||
|
||||
float OnVolumeChanged(Sound* sound, float volume) override
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
return cb(sound, volume);
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
};
|
||||
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||
ptr->cb = cb;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
#pragma once
|
||||
#include <kiwano-audio/Transcoder.h>
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/base/ObjectBase.h>
|
||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
#include <xaudio2.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -30,8 +29,10 @@ namespace kiwano
|
|||
namespace audio
|
||||
{
|
||||
class AudioModule;
|
||||
class SoundPlayer;
|
||||
|
||||
KGE_DECLARE_SMART_PTR(Sound);
|
||||
KGE_DECLARE_SMART_PTR(SoundCallback);
|
||||
|
||||
/**
|
||||
* \addtogroup Audio
|
||||
|
|
@ -40,13 +41,65 @@ KGE_DECLARE_SMART_PTR(Sound);
|
|||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频对象
|
||||
* @brief 音频回调
|
||||
*/
|
||||
class KGE_API Sound : public ObjectBase
|
||||
class KGE_API SoundCallback : public NativeObject
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 创建一个回调,在音频开始播放时执行
|
||||
static SoundCallbackPtr OnStart(const Function<void(Sound* sound)>& cb);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建一个回调,在音频循环结束时执行
|
||||
static SoundCallbackPtr OnLoopEnd(const Function<void(Sound* sound)>& cb);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建一个回调,在音频结束时执行
|
||||
static SoundCallbackPtr OnEnd(const Function<void(Sound* sound)>& cb);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建一个回调,在音频修改音量时执行
|
||||
static SoundCallbackPtr OnVolumeChanged(const Function<float(Sound* sound, float volume)>& cb);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在音频开始播放时执行
|
||||
virtual inline void OnStart(Sound* sound) {}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在音频循环结束时执行
|
||||
virtual inline void OnLoopEnd(Sound* sound) {}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在音频结束时执行
|
||||
virtual inline void OnEnd(Sound* sound) {}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在音频修改音量时执行
|
||||
virtual inline float OnVolumeChanged(Sound* sound, float volume)
|
||||
{
|
||||
return volume;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 音频
|
||||
*/
|
||||
class KGE_API Sound : public NativeObject
|
||||
{
|
||||
friend class AudioModule;
|
||||
friend class SoundPlayer;
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 预加载音频
|
||||
static SoundPtr Preload(const String& file_path, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 预加载音频资源
|
||||
static SoundPtr Preload(const Resource& res, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建音频对象
|
||||
/// @param res 本地音频文件路径
|
||||
|
|
@ -61,20 +114,6 @@ public:
|
|||
|
||||
virtual ~Sound();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 打开本地音频文件
|
||||
/// @param res 本地音频文件路径
|
||||
bool Load(const String& file_path);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 打开音频资源
|
||||
/// @param res 音频资源
|
||||
bool Load(const Resource& res);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 是否有效
|
||||
bool IsValid() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 播放
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
|
|
@ -109,28 +148,64 @@ public:
|
|||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||
void SetVolume(float volume);
|
||||
|
||||
private:
|
||||
IXAudio2SourceVoice* GetXAudio2Voice() const;
|
||||
/// \~chinese
|
||||
/// @brief 添加回调
|
||||
void AddCallback(SoundCallbackPtr callback);
|
||||
|
||||
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
|
||||
/// \~chinese
|
||||
/// @brief 获取所有回调
|
||||
List<SoundCallbackPtr>& GetCallbacks();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取所有回调
|
||||
const List<SoundCallbackPtr>& GetCallbacks() const;
|
||||
|
||||
protected:
|
||||
/// \~chinese
|
||||
/// @brief 打开本地音频文件
|
||||
/// @param res 本地音频文件路径
|
||||
bool Load(const String& file_path);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 打开音频资源
|
||||
/// @param res 音频资源
|
||||
bool Load(const Resource& res);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 打开音频资源
|
||||
/// @param res 音频资源
|
||||
bool Load(TranscoderPtr transcoder);
|
||||
|
||||
SoundCallbackPtr GetCallbackChain();
|
||||
|
||||
void ResetVolume();
|
||||
|
||||
private:
|
||||
bool opened_;
|
||||
bool playing_;
|
||||
Transcoder transcoder_;
|
||||
IXAudio2SourceVoice* voice_;
|
||||
bool opened_;
|
||||
bool playing_;
|
||||
float volume_;
|
||||
TranscoderPtr coder_;
|
||||
|
||||
SoundCallbackPtr callback_chain_;
|
||||
List<SoundCallbackPtr> callbacks_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
|
||||
inline List<SoundCallbackPtr>& kiwano::audio::Sound::GetCallbacks()
|
||||
{
|
||||
return voice_;
|
||||
return callbacks_;
|
||||
}
|
||||
|
||||
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
|
||||
inline const List<SoundCallbackPtr>& kiwano::audio::Sound::GetCallbacks() const
|
||||
{
|
||||
voice_ = voice;
|
||||
return callbacks_;
|
||||
}
|
||||
|
||||
inline void kiwano::audio::Sound::AddCallback(SoundCallbackPtr callback)
|
||||
{
|
||||
callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano-audio/SoundPlayer.h>
|
||||
#include <kiwano/platform/Application.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -28,85 +29,55 @@ namespace audio
|
|||
SoundPlayer::SoundPlayer()
|
||||
: volume_(1.f)
|
||||
{
|
||||
class SoundCallbackFunc : public SoundCallback
|
||||
{
|
||||
public:
|
||||
Function<void(Sound* sound)> cb_on_end;
|
||||
Function<float(Sound* sound, float volume)> cb_on_volume_changed;
|
||||
|
||||
void OnEnd(Sound* sound) override
|
||||
{
|
||||
cb_on_end(sound);
|
||||
}
|
||||
|
||||
float OnVolumeChanged(Sound* sound, float volume) override
|
||||
{
|
||||
return cb_on_volume_changed(sound, volume);
|
||||
}
|
||||
};
|
||||
auto cb = MakePtr<SoundCallbackFunc>();
|
||||
cb->cb_on_end = std::bind(&SoundPlayer::OnEnd, this, std::placeholders::_1);
|
||||
cb->cb_on_volume_changed =
|
||||
std::bind(&SoundPlayer::OnVolumeChanged, this, std::placeholders::_1, std::placeholders::_2);
|
||||
callback_ = cb;
|
||||
}
|
||||
|
||||
SoundPlayer::~SoundPlayer()
|
||||
{
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
size_t SoundPlayer::GetId(const String& file_path) const
|
||||
void SoundPlayer::Play(SoundPtr sound, int loop_count)
|
||||
{
|
||||
return std::hash<String>()(file_path);
|
||||
}
|
||||
|
||||
size_t SoundPlayer::GetId(const Resource& res) const
|
||||
{
|
||||
return static_cast<size_t>(res.GetId());
|
||||
}
|
||||
|
||||
size_t SoundPlayer::Load(const String& file_path)
|
||||
{
|
||||
size_t id = GetId(file_path);
|
||||
if (sound_cache_.end() != sound_cache_.find(id))
|
||||
return id;
|
||||
|
||||
SoundPtr sound = MakePtr<Sound>();
|
||||
if (sound && sound->Load(file_path))
|
||||
if (sound)
|
||||
{
|
||||
sound->SetVolume(volume_);
|
||||
sound_cache_.insert(std::make_pair(id, sound));
|
||||
return id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t SoundPlayer::Load(const Resource& res)
|
||||
{
|
||||
size_t id = GetId(res);
|
||||
if (sound_cache_.end() != sound_cache_.find(id))
|
||||
return id;
|
||||
|
||||
SoundPtr sound = MakePtr<Sound>();
|
||||
|
||||
if (sound && sound->Load(res))
|
||||
{
|
||||
sound->SetVolume(volume_);
|
||||
sound_cache_.insert(std::make_pair(id, sound));
|
||||
return id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SoundPlayer::Play(size_t id, int loop_count)
|
||||
{
|
||||
if (auto sound = GetSound(id))
|
||||
SetCallback(sound.Get());
|
||||
sound->Play(loop_count);
|
||||
sound_list_.push_back(sound);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayer::Pause(size_t id)
|
||||
SoundPtr SoundPlayer::Play(const String& file_path, int loop_count, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||
{
|
||||
if (auto sound = GetSound(id))
|
||||
sound->Pause();
|
||||
SoundPtr sound = Sound::Preload(file_path, callbacks);
|
||||
Play(sound, loop_count);
|
||||
return sound;
|
||||
}
|
||||
|
||||
void SoundPlayer::Resume(size_t id)
|
||||
SoundPtr SoundPlayer::Play(const Resource& res, int loop_count, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||
{
|
||||
if (auto sound = GetSound(id))
|
||||
sound->Resume();
|
||||
}
|
||||
|
||||
void SoundPlayer::Stop(size_t id)
|
||||
{
|
||||
if (auto sound = GetSound(id))
|
||||
sound->Stop();
|
||||
}
|
||||
|
||||
bool SoundPlayer::IsPlaying(size_t id)
|
||||
{
|
||||
if (auto sound = GetSound(id))
|
||||
return sound->IsPlaying();
|
||||
return false;
|
||||
SoundPtr sound = Sound::Preload(res, callbacks);
|
||||
Play(sound, loop_count);
|
||||
return sound;
|
||||
}
|
||||
|
||||
float SoundPlayer::GetVolume() const
|
||||
|
|
@ -116,48 +87,81 @@ float SoundPlayer::GetVolume() const
|
|||
|
||||
void SoundPlayer::SetVolume(float volume)
|
||||
{
|
||||
volume_ = std::min(std::max(volume, -224.f), 224.f);
|
||||
for (auto& pair : sound_cache_)
|
||||
{
|
||||
pair.second->SetVolume(volume_);
|
||||
}
|
||||
}
|
||||
|
||||
SoundPtr SoundPlayer::GetSound(size_t id) const
|
||||
{
|
||||
auto iter = sound_cache_.find(id);
|
||||
if (iter != sound_cache_.end())
|
||||
return iter->second;
|
||||
return SoundPtr();
|
||||
volume_ = volume;
|
||||
}
|
||||
|
||||
void SoundPlayer::PauseAll()
|
||||
{
|
||||
for (auto& pair : sound_cache_)
|
||||
for (auto& sound : sound_list_)
|
||||
{
|
||||
pair.second->Pause();
|
||||
sound->Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayer::ResumeAll()
|
||||
{
|
||||
for (auto& pair : sound_cache_)
|
||||
for (auto& sound : sound_list_)
|
||||
{
|
||||
pair.second->Resume();
|
||||
sound->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayer::StopAll()
|
||||
{
|
||||
for (auto& pair : sound_cache_)
|
||||
for (auto& sound : sound_list_)
|
||||
{
|
||||
pair.second->Stop();
|
||||
sound->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayer::ClearCache()
|
||||
void SoundPlayer::OnEnd(Sound* sound)
|
||||
{
|
||||
sound_cache_.clear();
|
||||
// remove callback
|
||||
RemoveCallback(sound);
|
||||
|
||||
// remove sound after stopped
|
||||
auto iter = std::find(sound_list_.begin(), sound_list_.end(), sound);
|
||||
if (iter != sound_list_.end())
|
||||
{
|
||||
trash_.push_back(*iter);
|
||||
sound_list_.erase(iter);
|
||||
}
|
||||
|
||||
// clear trash in main thread
|
||||
Application::GetInstance().PerformInMainThread(std::bind(&SoundPlayer::ClearTrash, this));
|
||||
}
|
||||
|
||||
float SoundPlayer::OnVolumeChanged(Sound* sound, float volume)
|
||||
{
|
||||
return volume * volume_;
|
||||
}
|
||||
|
||||
void SoundPlayer::SetCallback(Sound* sound)
|
||||
{
|
||||
// add callback if not exists
|
||||
auto& cbs = sound->GetCallbacks();
|
||||
auto iter = std::find(cbs.begin(), cbs.end(), callback_);
|
||||
if (iter == cbs.end())
|
||||
{
|
||||
sound->AddCallback(callback_);
|
||||
}
|
||||
sound->ResetVolume();
|
||||
}
|
||||
|
||||
void SoundPlayer::RemoveCallback(Sound* sound)
|
||||
{
|
||||
auto& cbs = sound->GetCallbacks();
|
||||
auto iter = std::find(cbs.begin(), cbs.end(), callback_);
|
||||
if (iter != cbs.end())
|
||||
{
|
||||
*iter = nullptr; // will be removed by sound
|
||||
}
|
||||
}
|
||||
|
||||
void SoundPlayer::ClearTrash()
|
||||
{
|
||||
trash_.clear();
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano-audio/Sound.h>
|
||||
#include <kiwano/base/ObjectBase.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -40,73 +39,31 @@ KGE_DECLARE_SMART_PTR(SoundPlayer);
|
|||
class KGE_API SoundPlayer : public ObjectBase
|
||||
{
|
||||
public:
|
||||
using SoundList = List<SoundPtr>;
|
||||
|
||||
SoundPlayer();
|
||||
|
||||
~SoundPlayer();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 加载本地音频文件
|
||||
/// @param file_path 本地音频文件路径
|
||||
/// @return 音频标识符
|
||||
size_t Load(const String& file_path);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 加载音频资源
|
||||
/// @param res 音频资源
|
||||
/// @return 音频标识符
|
||||
size_t Load(const Resource& res);
|
||||
/// @brief 播放音频
|
||||
/// @param sound 音频
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
void Play(SoundPtr sound, 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 Resume(size_t id);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 停止音频
|
||||
/// @param id 音频标识符
|
||||
void Stop(size_t id);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取音频播放状态
|
||||
/// @param id 音频标识符
|
||||
bool IsPlaying(size_t id);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取音量
|
||||
float GetVolume() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置音量
|
||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||
void SetVolume(float volume);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取本地音频文件id
|
||||
/// @param file_path 本地音频文件路径
|
||||
/// @return 音频标识符
|
||||
size_t GetId(const String& file_path) const;
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
/// @param callbacks 注册回调
|
||||
SoundPtr Play(const String& file_path, int loop_count = 0, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取音频资源id
|
||||
/// @brief 播放音频
|
||||
/// @param res 音频资源
|
||||
/// @return 音频标识符
|
||||
size_t GetId(const Resource& res) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取音乐对象
|
||||
/// @param id 音频标识符
|
||||
SoundPtr GetSound(size_t id) const;
|
||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||
/// @param callbacks 注册回调
|
||||
SoundPtr Play(const Resource& res, int loop_count = 0, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 暂停所有音频
|
||||
|
|
@ -121,16 +78,42 @@ public:
|
|||
void StopAll();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 清除缓存
|
||||
void ClearCache();
|
||||
/// @brief 获取正在播放的音频列表
|
||||
const SoundList& GetPlayingList() const;
|
||||
|
||||
private:
|
||||
float volume_;
|
||||
/// \~chinese
|
||||
/// @brief 获取音量
|
||||
float GetVolume() const;
|
||||
|
||||
using SoundMap = Map<size_t, SoundPtr>;
|
||||
SoundMap sound_cache_;
|
||||
/// \~chinese
|
||||
/// @brief 设置音量
|
||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||
void SetVolume(float volume);
|
||||
|
||||
protected:
|
||||
void OnEnd(Sound* sound);
|
||||
|
||||
float OnVolumeChanged(Sound* sound, float volume);
|
||||
|
||||
void SetCallback(Sound* sound);
|
||||
|
||||
void RemoveCallback(Sound* sound);
|
||||
|
||||
void ClearTrash();
|
||||
|
||||
protected:
|
||||
float volume_;
|
||||
SoundList sound_list_;
|
||||
SoundList trash_;
|
||||
SoundCallbackPtr callback_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
inline const SoundPlayer::SoundList& SoundPlayer::GetPlayingList() const
|
||||
{
|
||||
return sound_list_;
|
||||
}
|
||||
|
||||
} // namespace audio
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/base/ObjectBase.h>
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
#include <mfreadwrite.h>
|
||||
|
|
@ -28,7 +29,9 @@ namespace kiwano
|
|||
{
|
||||
namespace audio
|
||||
{
|
||||
class Sound;
|
||||
class AudioModule;
|
||||
|
||||
KGE_DECLARE_SMART_PTR(Transcoder);
|
||||
|
||||
/**
|
||||
* \addtogroup Audio
|
||||
|
|
@ -39,9 +42,9 @@ class Sound;
|
|||
* \~chinese
|
||||
* @brief 音频解码器
|
||||
*/
|
||||
class KGE_API Transcoder
|
||||
class KGE_API Transcoder : public ObjectBase
|
||||
{
|
||||
friend class Sound;
|
||||
friend class AudioModule;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
@ -86,6 +89,56 @@ private:
|
|||
WAVEFORMATEX* wave_format_;
|
||||
};
|
||||
|
||||
|
||||
class KGE_API TranscoderCache final : public Singleton<TranscoderCache>
|
||||
{
|
||||
friend Singleton<TranscoderCache>;
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 警속뻠닸
|
||||
inline void Add(size_t key, TranscoderPtr v)
|
||||
{
|
||||
cache_.insert(std::make_pair(key, v));
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 삿혤뻠닸
|
||||
inline TranscoderPtr Get(size_t key) const
|
||||
{
|
||||
if (cache_.count(key))
|
||||
{
|
||||
return cache_.at(key);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 盧뇜뻠닸
|
||||
inline void Remove(size_t key)
|
||||
{
|
||||
cache_.erase(key);
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 헌왕뻠닸
|
||||
inline void Clear()
|
||||
{
|
||||
cache_.clear();
|
||||
}
|
||||
|
||||
~TranscoderCache()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
private:
|
||||
TranscoderCache() = default;
|
||||
|
||||
private:
|
||||
UnorderedMap<size_t, TranscoderPtr> cache_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
} // namespace audio
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ void HttpModule::NetworkThread()
|
|||
response_queue_.push(response);
|
||||
response_mutex_.unlock();
|
||||
|
||||
Application::GetInstance().PreformInMainThread(Closure(this, &HttpModule::DispatchResponseCallback));
|
||||
Application::GetInstance().PerformInMainThread(Closure(this, &HttpModule::DispatchResponseCallback));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class PhysicWorld::DebugDrawer : public b2Draw
|
|||
public:
|
||||
DebugDrawer(const Size& size)
|
||||
{
|
||||
canvas_ = MakePtr<Canvas>(size);
|
||||
canvas_ = MakePtr<Canvas>(PixelSize(uint32_t(size.x), uint32_t(size.y)));
|
||||
ctx_ = canvas_->GetContext2D();
|
||||
|
||||
b2Draw::SetFlags(b2Draw::e_shapeBit | b2Draw::e_jointBit | b2Draw::e_jointBit | b2Draw::e_centerOfMassBit);
|
||||
|
|
|
|||
|
|
@ -25,10 +25,9 @@ namespace kiwano
|
|||
{
|
||||
Canvas::Canvas()
|
||||
{
|
||||
RecreateContext(nullptr);
|
||||
}
|
||||
|
||||
Canvas::Canvas(const Size& size)
|
||||
Canvas::Canvas(const PixelSize& size)
|
||||
{
|
||||
ResizeAndClear(size);
|
||||
}
|
||||
|
|
@ -39,24 +38,10 @@ CanvasRenderContextPtr Canvas::GetContext2D() const
|
|||
return ctx;
|
||||
}
|
||||
|
||||
void Canvas::ResizeAndClear(Size size)
|
||||
{
|
||||
RecreateContext(&size);
|
||||
}
|
||||
|
||||
void Canvas::RecreateContext(Size* size)
|
||||
void Canvas::ResizeAndClear(const PixelSize& size)
|
||||
{
|
||||
texture_cached_ = MakePtr<Texture>();
|
||||
|
||||
if (size)
|
||||
{
|
||||
render_ctx_ = RenderContext::Create(*texture_cached_, *size);
|
||||
}
|
||||
else
|
||||
{
|
||||
render_ctx_ = RenderContext::Create(*texture_cached_);
|
||||
}
|
||||
|
||||
render_ctx_ = RenderContext::Create(texture_cached_, size);
|
||||
if (render_ctx_)
|
||||
{
|
||||
SetSize(render_ctx_->GetSize());
|
||||
|
|
@ -67,11 +52,6 @@ void Canvas::RecreateContext(Size* size)
|
|||
}
|
||||
}
|
||||
|
||||
TexturePtr Canvas::ExportToTexture() const
|
||||
{
|
||||
return texture_cached_;
|
||||
}
|
||||
|
||||
void Canvas::OnRender(RenderContext& ctx)
|
||||
{
|
||||
if (texture_cached_)
|
||||
|
|
|
|||
|
|
@ -43,12 +43,15 @@ KGE_DECLARE_SMART_PTR(CanvasRenderContext);
|
|||
class KGE_API Canvas : public Actor
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 创建画布
|
||||
/// @warning 必须调用 ResizeAndClear 以初始化画布
|
||||
Canvas();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建画布
|
||||
/// @param size 画布大小
|
||||
Canvas(const Size& size);
|
||||
Canvas(const PixelSize& size);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取2D绘图上下文
|
||||
|
|
@ -57,17 +60,14 @@ public:
|
|||
/// \~chinese
|
||||
/// @brief 清空画布大小并重设画布大小
|
||||
/// @warning 该函数会导致原绘图上下文失效
|
||||
void ResizeAndClear(Size size);
|
||||
void ResizeAndClear(const PixelSize& size);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 导出纹理
|
||||
TexturePtr ExportToTexture() const;
|
||||
TexturePtr GetTexture() const;
|
||||
|
||||
void OnRender(RenderContext& ctx) override;
|
||||
|
||||
private:
|
||||
void RecreateContext(Size* size);
|
||||
|
||||
private:
|
||||
TexturePtr texture_cached_;
|
||||
RenderContextPtr render_ctx_;
|
||||
|
|
@ -86,6 +86,11 @@ public:
|
|||
/// @brief 结束渲染
|
||||
void EndDraw();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 画角色
|
||||
/// @param actor 角色
|
||||
void DrawActor(ActorPtr actor);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 画形状轮廓
|
||||
/// @param shape 形状
|
||||
|
|
@ -285,6 +290,11 @@ private:
|
|||
|
||||
/** @} */
|
||||
|
||||
inline TexturePtr Canvas::GetTexture() const
|
||||
{
|
||||
return texture_cached_;
|
||||
}
|
||||
|
||||
inline void CanvasRenderContext::BeginDraw()
|
||||
{
|
||||
KGE_ASSERT(ctx_);
|
||||
|
|
@ -297,6 +307,15 @@ inline void CanvasRenderContext::EndDraw()
|
|||
ctx_->EndDraw();
|
||||
}
|
||||
|
||||
inline void CanvasRenderContext::DrawActor(ActorPtr actor)
|
||||
{
|
||||
KGE_ASSERT(ctx_);
|
||||
if (actor)
|
||||
{
|
||||
actor->OnRender(*ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CanvasRenderContext::DrawShape(ShapePtr shape)
|
||||
{
|
||||
KGE_ASSERT(ctx_);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <kiwano/2d/GifSprite.h>
|
||||
#include <kiwano/render/RenderContext.h>
|
||||
#include <kiwano/render/Renderer.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -76,9 +77,8 @@ bool GifSprite::Load(GifImagePtr gif)
|
|||
frame_to_render_.Reset();
|
||||
frame_rt_.Reset();
|
||||
|
||||
Size frame_size = Size(float(gif_->GetWidthInPixels()), float(gif_->GetHeightInPixels()));
|
||||
frame_to_render_ = MakePtr<Texture>();
|
||||
frame_rt_ = RenderContext::Create(*frame_to_render_, frame_size);
|
||||
frame_rt_ = RenderContext::Create(frame_to_render_, gif_->GetSizeInPixels());
|
||||
|
||||
if (frame_rt_)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -289,7 +289,8 @@ void TextActor::UpdateCachedTexture()
|
|||
const auto expectedSize = layout_->GetSize() + cached_texture_offset * 2;
|
||||
if (!render_ctx_)
|
||||
{
|
||||
render_ctx_ = RenderContext::Create(*texture_cached_, expectedSize);
|
||||
const auto pixelSize = PixelSize((uint32_t)math::Ceil(expectedSize.x), (uint32_t)math::Ceil(expectedSize.y));
|
||||
render_ctx_ = RenderContext::Create(texture_cached_, pixelSize);
|
||||
}
|
||||
else if (render_ctx_->GetSize() != expectedSize)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ set(SOURCE_FILES
|
|||
math/Transform.hpp
|
||||
math/Vec2.hpp
|
||||
platform/win32/ComPtr.hpp
|
||||
platform/win32/ComObject.cpp
|
||||
platform/win32/ComObject.h
|
||||
platform/win32/libraries.cpp
|
||||
platform/win32/libraries.h
|
||||
platform/win32/WindowImpl.cpp
|
||||
|
|
@ -113,6 +115,8 @@ set(SOURCE_FILES
|
|||
platform/Runner.h
|
||||
platform/Window.cpp
|
||||
platform/Window.h
|
||||
platform/NativeObject.cpp
|
||||
platform/NativeObject.h
|
||||
render/DirectX/D2DDeviceResources.cpp
|
||||
render/DirectX/D2DDeviceResources.h
|
||||
render/DirectX/D3D10DeviceResources.cpp
|
||||
|
|
@ -123,7 +127,6 @@ set(SOURCE_FILES
|
|||
render/DirectX/FontCollectionLoader.cpp
|
||||
render/DirectX/FontCollectionLoader.h
|
||||
render/DirectX/helper.h
|
||||
render/DirectX/NativePtr.h
|
||||
render/DirectX/RenderContextImpl.cpp
|
||||
render/DirectX/RenderContextImpl.h
|
||||
render/DirectX/RendererImpl.cpp
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ void Application::Render()
|
|||
renderer.Present();
|
||||
}
|
||||
|
||||
void Application::PreformInMainThread(Function<void()> func)
|
||||
void Application::PerformInMainThread(Function<void()> func)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(perform_mutex_);
|
||||
functions_to_perform_.push(func);
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ public:
|
|||
* @details 提供在其他线程调用 Kiwano 函数的能力
|
||||
* @param func 需要执行的函数
|
||||
*/
|
||||
void PreformInMainThread(Function<void()> func);
|
||||
void PerformInMainThread(Function<void()> func);
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
|
|
|
|||
|
|
@ -21,73 +21,69 @@
|
|||
#pragma once
|
||||
#include <kiwano/base/ObjectBase.h>
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/D2DDeviceResources.h>
|
||||
#endif
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
KGE_DECLARE_SMART_PTR(NativeObject);
|
||||
|
||||
/**
|
||||
* \addtogroup Render
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 含有本地指针的对象
|
||||
*/
|
||||
class KGE_API NativeObjectBase : public ObjectBase
|
||||
class KGE_API NativeObject : public ObjectBase
|
||||
{
|
||||
public:
|
||||
NativeObjectBase();
|
||||
NativeObject() = default;
|
||||
|
||||
bool IsValid() const override;
|
||||
const Any& GetNative() const;
|
||||
|
||||
void* GetNativePointer() const;
|
||||
template <class _Ty>
|
||||
_Ty GetNative() const;
|
||||
|
||||
template <typename _NativeTy>
|
||||
_NativeTy* GetNativePointer() const;
|
||||
template<class _Ty>
|
||||
_Ty* GetNativePtr() const;
|
||||
|
||||
virtual void ResetNativePointer(void* native_pointer = nullptr);
|
||||
void SetNative(const Any& native);
|
||||
|
||||
void ResetNative();
|
||||
|
||||
protected:
|
||||
void* native_pointer_;
|
||||
Any native_;
|
||||
};
|
||||
|
||||
#if defined(KGE_PLATFORM_WINDOWS)
|
||||
|
||||
class KGE_API NativeObject : public NativeObjectBase
|
||||
inline const Any& NativeObject::GetNative() const
|
||||
{
|
||||
public:
|
||||
virtual ~NativeObject();
|
||||
|
||||
void ResetNativePointer(void* native_pointer = nullptr) override;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
typedef NativeObjectBase NativeObject;
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
inline void* NativeObjectBase::GetNativePointer() const
|
||||
{
|
||||
return native_pointer_;
|
||||
return native_;
|
||||
}
|
||||
|
||||
template <typename _NativeTy>
|
||||
inline _NativeTy* NativeObjectBase::GetNativePointer() const
|
||||
template <class _Ty>
|
||||
inline _Ty NativeObject::GetNative() const
|
||||
{
|
||||
if (native_pointer_ != nullptr)
|
||||
if (native_.HasValue())
|
||||
{
|
||||
return static_cast<_NativeTy*>(native_pointer_);
|
||||
return native_.Cast<_Ty>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class _Ty>
|
||||
inline _Ty* NativeObject::GetNativePtr() const
|
||||
{
|
||||
if (native_.HasValue())
|
||||
{
|
||||
return native_.Cast<_Ty*>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void NativeObject::SetNative(const Any& native)
|
||||
{
|
||||
native_ = native;
|
||||
}
|
||||
|
||||
inline void NativeObject::ResetNative()
|
||||
{
|
||||
native_.Clear();
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -22,11 +22,12 @@
|
|||
#include <type_traits>
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/core/RefBasePtr.hpp>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
#include <Unknwnbase.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
struct ComPtrPolicy
|
||||
struct ComRefPolicy
|
||||
{
|
||||
inline void Retain(IUnknown* ptr)
|
||||
{
|
||||
|
|
@ -43,6 +44,74 @@ struct ComPtrPolicy
|
|||
|
||||
// ComPtr<> is a smart pointer for COM
|
||||
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
|
||||
using ComPtr = RefBasePtr<_Ty, ComPtrPolicy>;
|
||||
using ComPtr = RefBasePtr<_Ty, ComRefPolicy>;
|
||||
|
||||
struct ComPolicy
|
||||
{
|
||||
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
|
||||
static inline ComPtr<_Ty> Get(const NativeObject* object)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
const auto& native = object->GetNative();
|
||||
if (native.HasValue())
|
||||
{
|
||||
auto ptr = native.Cast<ComPtr<IUnknown>>();
|
||||
if (ptr)
|
||||
{
|
||||
ComPtr<_Ty> native;
|
||||
if (SUCCEEDED(ptr->QueryInterface<_Ty>(&native)))
|
||||
return native;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
|
||||
static inline ComPtr<_Ty> Get(const NativeObject& object)
|
||||
{
|
||||
return ComPolicy::Get<_Ty>(&object);
|
||||
}
|
||||
|
||||
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
|
||||
static inline ComPtr<_Ty> Get(NativeObjectPtr object)
|
||||
{
|
||||
return ComPolicy::Get<_Ty>(object.Get());
|
||||
}
|
||||
|
||||
static inline void Set(NativeObject* object, ComPtr<IUnknown> com_ptr)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
object->SetNative(Any{ com_ptr });
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Set(NativeObject* object, IUnknown* com_ptr)
|
||||
{
|
||||
ComPolicy::Set(object, ComPtr<IUnknown>(com_ptr));
|
||||
}
|
||||
|
||||
static inline void Set(NativeObject& object, IUnknown* com_ptr)
|
||||
{
|
||||
ComPolicy::Set(&object, com_ptr);
|
||||
}
|
||||
|
||||
static inline void Set(NativeObjectPtr object, IUnknown* com_ptr)
|
||||
{
|
||||
ComPolicy::Set(object.Get(), com_ptr);
|
||||
}
|
||||
|
||||
static inline void Set(NativeObject& object, ComPtr<IUnknown> com_ptr)
|
||||
{
|
||||
ComPolicy::Set(&object, com_ptr.Get());
|
||||
}
|
||||
|
||||
static inline void Set(NativeObjectPtr object, ComPtr<IUnknown> com_ptr)
|
||||
{
|
||||
ComPolicy::Set(object.Get(), com_ptr.Get());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#include <kiwano/render/Renderer.h>
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
#endif
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -124,7 +124,7 @@ void Brush::SetTransform(const Transform& transform)
|
|||
void Brush::SetTransform(const Matrix3x2& transform)
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1Brush>(this);
|
||||
auto native = ComPolicy::Get<ID2D1Brush>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
#include <kiwano/render/Color.h>
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/render/Texture.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
|
|||
|
|
@ -92,8 +92,6 @@ public:
|
|||
|
||||
void DiscardResources() override;
|
||||
|
||||
void SetTargetBitmap(_In_ ComPtr<ID2D1Bitmap1> target) override;
|
||||
|
||||
void ResetTextRenderingParams(_In_ HMONITOR monitor) override;
|
||||
|
||||
public:
|
||||
|
|
@ -213,7 +211,6 @@ void D2DDeviceResources::DiscardResources()
|
|||
}
|
||||
}
|
||||
|
||||
target_bitmap_.Reset();
|
||||
device_context_.Reset();
|
||||
device_.Reset();
|
||||
|
||||
|
|
@ -315,7 +312,7 @@ HRESULT D2DDeviceResources::CreateDeviceResources(_In_ ComPtr<IDXGIDevice> dxgi_
|
|||
{
|
||||
ComPtr<ID2D1DeviceContext> device_ctx;
|
||||
|
||||
hr = device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &device_ctx);
|
||||
hr = device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, &device_ctx);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -350,7 +347,7 @@ HRESULT D2DDeviceResources::CreateWindowSizeDependentResources()
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
SetTargetBitmap(target);
|
||||
device_context_->SetTarget(target.Get());
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
|
|
@ -384,15 +381,6 @@ HRESULT D2DDeviceResources::HandleDeviceLost(_In_ ComPtr<IDXGIDevice> dxgi_devic
|
|||
return hr;
|
||||
}
|
||||
|
||||
void D2DDeviceResources::SetTargetBitmap(ComPtr<ID2D1Bitmap1> target)
|
||||
{
|
||||
target_bitmap_ = target;
|
||||
if (device_context_)
|
||||
{
|
||||
device_context_->SetTarget(target_bitmap_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
void D2DDeviceResources::ResetTextRenderingParams(HMONITOR monitor)
|
||||
{
|
||||
if (!dwrite_factory_ || device_context_)
|
||||
|
|
|
|||
|
|
@ -78,8 +78,6 @@ public:
|
|||
|
||||
virtual void DiscardResources() = 0;
|
||||
|
||||
virtual void SetTargetBitmap(_In_ ComPtr<ID2D1Bitmap1> target) = 0;
|
||||
|
||||
virtual void ResetTextRenderingParams(_In_ HMONITOR monitor) = 0;
|
||||
|
||||
inline ID2D1Factory1* GetFactory()
|
||||
|
|
@ -112,17 +110,10 @@ public:
|
|||
return device_context_.Get();
|
||||
}
|
||||
|
||||
inline ID2D1Bitmap1* GetTargetBitmap()
|
||||
{
|
||||
KGE_ASSERT(target_bitmap_);
|
||||
return target_bitmap_.Get();
|
||||
}
|
||||
|
||||
protected:
|
||||
ComPtr<ID2D1Factory1> factory_;
|
||||
ComPtr<ID2D1Device> device_;
|
||||
ComPtr<ID2D1DeviceContext> device_context_;
|
||||
ComPtr<ID2D1Bitmap1> target_bitmap_;
|
||||
|
||||
ComPtr<IWICImagingFactory> imaging_factory_;
|
||||
ComPtr<IDWriteFactory> dwrite_factory_;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FontCollectionLoader
|
||||
|
|
@ -41,7 +45,7 @@ public:
|
|||
|
||||
// IDWriteFontCollectionLoader methods
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(IDWriteFactory* pFactory, void const* collectionKey,
|
||||
uint32_t collectionKeySize,
|
||||
uint32_t collectionKeySize,
|
||||
_Out_ IDWriteFontFileEnumerator** fontFileEnumerator);
|
||||
|
||||
// IUnknown methods
|
||||
|
|
@ -348,7 +352,7 @@ public:
|
|||
|
||||
// IDWriteFontCollectionLoader methods
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(IDWriteFactory* pFactory, void const* collectionKey,
|
||||
uint32_t collectionKeySize,
|
||||
uint32_t collectionKeySize,
|
||||
_Out_ IDWriteFontFileEnumerator** fontFileEnumerator);
|
||||
|
||||
// IUnknown methods
|
||||
|
|
@ -389,8 +393,7 @@ HRESULT IResourceFontCollectionLoader::Create(_Out_ IResourceFontCollectionLoade
|
|||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP ResourceFontCollectionLoader::AddResources(const Vector<BinaryData>& data,
|
||||
_Out_ LPVOID* pCollectionKey,
|
||||
STDMETHODIMP ResourceFontCollectionLoader::AddResources(const Vector<BinaryData>& data, _Out_ LPVOID* pCollectionKey,
|
||||
_Out_ uint32_t* pCollectionKeySize)
|
||||
{
|
||||
if (!pCollectionKey || !pCollectionKeySize)
|
||||
|
|
@ -492,8 +495,8 @@ public:
|
|||
}
|
||||
|
||||
// IDWriteFontFileLoader methods
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
|
||||
uint32_t fontFileReferenceKeySize,
|
||||
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
|
||||
uint32_t fontFileReferenceKeySize,
|
||||
_Out_ IDWriteFontFileStream** fontFileStream);
|
||||
|
||||
// IUnknown methods
|
||||
|
|
@ -891,4 +894,6 @@ ULONG STDMETHODCALLTYPE ResourceFontFileStream::Release()
|
|||
return newCount;
|
||||
}
|
||||
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -21,10 +21,13 @@
|
|||
#pragma once
|
||||
#include <kiwano/core/BinaryData.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
interface DWRITE_DECLARE_INTERFACE("7EC7A55A-1964-4098-83E0-EFA7C12C6EF7") IFontCollectionLoader
|
||||
: public IDWriteFontCollectionLoader
|
||||
{
|
||||
|
|
@ -78,4 +81,6 @@ public:
|
|||
static HRESULT Create(_Out_ IResourceFontFileStream** ppStream, const BinaryData& data);
|
||||
};
|
||||
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||
#include <unknwn.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
class KGE_API NativePtr
|
||||
{
|
||||
public:
|
||||
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
|
||||
static inline ComPtr<_Ty> Get(const NativeObject* object)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
ComPtr<IUnknown> ptr = object->GetNativePointer<IUnknown>();
|
||||
if (ptr)
|
||||
{
|
||||
ComPtr<_Ty> native;
|
||||
if (SUCCEEDED(ptr->QueryInterface<_Ty>(&native)))
|
||||
return native;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static inline ComPtr<_Ty> Get(const NativeObject& object)
|
||||
{
|
||||
return NativePtr::Get<_Ty>(&object);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static inline ComPtr<_Ty> Get(NativeObjectPtr object)
|
||||
{
|
||||
return NativePtr::Get<_Ty>(object.Get());
|
||||
}
|
||||
|
||||
static inline void Set(NativeObject* object, ComPtr<IUnknown> com_ptr)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
object->ResetNativePointer(com_ptr.Get());
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Set(NativeObject& object, ComPtr<IUnknown> com_ptr)
|
||||
{
|
||||
NativePtr::Set(&object, com_ptr);
|
||||
}
|
||||
|
||||
static inline void Set(NativeObjectPtr object, ComPtr<IUnknown> com_ptr)
|
||||
{
|
||||
NativePtr::Set(object.Get(), com_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -19,13 +19,15 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/render/DirectX/RenderContextImpl.h>
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/Renderer.h>
|
||||
#include <kiwano/utils/Logger.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
RenderContextImpl::RenderContextImpl() {}
|
||||
|
||||
RenderContextImpl::~RenderContextImpl()
|
||||
|
|
@ -33,23 +35,23 @@ RenderContextImpl::~RenderContextImpl()
|
|||
DiscardDeviceResources();
|
||||
}
|
||||
|
||||
HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> render_target)
|
||||
HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1DeviceContext> ctx)
|
||||
{
|
||||
if (!factory || !render_target)
|
||||
if (!factory || !ctx)
|
||||
return E_INVALIDARG;
|
||||
|
||||
render_target_ = render_target;
|
||||
render_ctx_ = ctx;
|
||||
text_renderer_.Reset();
|
||||
current_brush_.Reset();
|
||||
|
||||
HRESULT hr = ITextRenderer::Create(&text_renderer_, render_target_.Get());
|
||||
HRESULT hr = ITextRenderer::Create(&text_renderer_, render_ctx_.Get());
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
SetAntialiasMode(antialias_);
|
||||
SetTextAntialiasMode(text_antialias_);
|
||||
|
||||
Resize(reinterpret_cast<const Size&>(render_target->GetSize()));
|
||||
Resize(reinterpret_cast<const Size&>(render_ctx_->GetSize()));
|
||||
}
|
||||
|
||||
// DrawingStateBlock
|
||||
|
|
@ -60,7 +62,7 @@ HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, C
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(this, render_target);
|
||||
ComPolicy::Set(this, ctx);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -68,28 +70,42 @@ HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, C
|
|||
void RenderContextImpl::DiscardDeviceResources()
|
||||
{
|
||||
text_renderer_.Reset();
|
||||
render_target_.Reset();
|
||||
render_ctx_.Reset();
|
||||
current_brush_.Reset();
|
||||
|
||||
ResetNativePointer();
|
||||
ComPolicy::Set(this, nullptr);
|
||||
}
|
||||
|
||||
TexturePtr RenderContextImpl::GetTarget() const
|
||||
{
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
ComPtr<ID2D1Image> target;
|
||||
render_ctx_->GetTarget(&target);
|
||||
if (target)
|
||||
{
|
||||
TexturePtr ptr = MakePtr<Texture>();
|
||||
ComPolicy::Set(*ptr, target.Get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RenderContextImpl::BeginDraw()
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
SaveDrawingState();
|
||||
|
||||
RenderContext::BeginDraw();
|
||||
|
||||
render_target_->BeginDraw();
|
||||
render_ctx_->BeginDraw();
|
||||
}
|
||||
|
||||
void RenderContextImpl::EndDraw()
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
HRESULT hr = render_target_->EndDraw();
|
||||
HRESULT hr = render_ctx_->EndDraw();
|
||||
KGE_THROW_IF_FAILED(hr, "ID2D1RenderTarget EndDraw failed");
|
||||
|
||||
RenderContext::EndDraw();
|
||||
|
|
@ -97,9 +113,25 @@ void RenderContextImpl::EndDraw()
|
|||
RestoreDrawingState();
|
||||
}
|
||||
|
||||
void RenderContextImpl::CreateTexture(Texture& texture, const PixelSize& size)
|
||||
{
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
ComPtr<ID2D1Bitmap> saved_bitmap;
|
||||
|
||||
HRESULT hr = render_ctx_->CreateBitmap(D2D1::SizeU(size.x, size.y), D2D1::BitmapProperties(), &saved_bitmap);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPolicy::Set(texture, saved_bitmap);
|
||||
}
|
||||
|
||||
KGE_THROW_IF_FAILED(hr, "Create texture failed");
|
||||
}
|
||||
|
||||
void RenderContextImpl::DrawTexture(const Texture& texture, const Rect* src_rect, const Rect* dest_rect)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
if (texture.IsValid())
|
||||
{
|
||||
|
|
@ -113,8 +145,8 @@ void RenderContextImpl::DrawTexture(const Texture& texture, const Rect* src_rect
|
|||
mode = D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
|
||||
}
|
||||
|
||||
auto bitmap = NativePtr::Get<ID2D1Bitmap>(texture);
|
||||
render_target_->DrawBitmap(bitmap.Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, brush_opacity_,
|
||||
auto bitmap = ComPolicy::Get<ID2D1Bitmap>(texture);
|
||||
render_ctx_->DrawBitmap(bitmap.Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, brush_opacity_,
|
||||
mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -127,10 +159,10 @@ void RenderContextImpl::DrawTextLayout(const TextLayout& layout, const Point& of
|
|||
|
||||
if (layout.IsValid())
|
||||
{
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(layout);
|
||||
auto fill_brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto outline_brush = NativePtr::Get<ID2D1Brush>(current_outline_brush);
|
||||
auto outline_stroke = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(layout);
|
||||
auto fill_brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto outline_brush = ComPolicy::Get<ID2D1Brush>(current_outline_brush);
|
||||
auto outline_stroke = ComPolicy::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
float outline_width = 1.0f;
|
||||
|
||||
if (fill_brush)
|
||||
|
|
@ -164,17 +196,17 @@ void RenderContextImpl::DrawTextLayout(const TextLayout& layout, const Point& of
|
|||
|
||||
void RenderContextImpl::DrawShape(const Shape& shape)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
if (shape.IsValid())
|
||||
{
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(shape);
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = ComPolicy::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
||||
|
||||
render_target_->DrawGeometry(geometry.Get(), brush.Get(), stroke_width, stroke_style.Get());
|
||||
render_ctx_->DrawGeometry(geometry.Get(), brush.Get(), stroke_width, stroke_style.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -182,14 +214,14 @@ void RenderContextImpl::DrawShape(const Shape& shape)
|
|||
|
||||
void RenderContextImpl::DrawLine(const Point& point1, const Point& point2)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = ComPolicy::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
||||
|
||||
render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), brush.Get(), stroke_width,
|
||||
render_ctx_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), brush.Get(), stroke_width,
|
||||
stroke_style.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -197,28 +229,28 @@ void RenderContextImpl::DrawLine(const Point& point1, const Point& point2)
|
|||
|
||||
void RenderContextImpl::DrawRectangle(const Rect& rect)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = ComPolicy::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
||||
|
||||
render_target_->DrawRectangle(DX::ConvertToRectF(rect), brush.Get(), stroke_width, stroke_style.Get());
|
||||
render_ctx_->DrawRectangle(DX::ConvertToRectF(rect), brush.Get(), stroke_width, stroke_style.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
||||
void RenderContextImpl::DrawRoundedRectangle(const Rect& rect, const Vec2& radius)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = ComPolicy::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
||||
|
||||
render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get(),
|
||||
render_ctx_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get(),
|
||||
stroke_width, stroke_style.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -226,14 +258,14 @@ void RenderContextImpl::DrawRoundedRectangle(const Rect& rect, const Vec2& radiu
|
|||
|
||||
void RenderContextImpl::DrawEllipse(const Point& center, const Vec2& radius)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = NativePtr::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto stroke_style = ComPolicy::Get<ID2D1StrokeStyle>(current_stroke_);
|
||||
float stroke_width = current_stroke_ ? current_stroke_->GetWidth() : 1.0f;
|
||||
|
||||
render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get(),
|
||||
render_ctx_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get(),
|
||||
stroke_width, stroke_style.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -241,14 +273,14 @@ void RenderContextImpl::DrawEllipse(const Point& center, const Vec2& radius)
|
|||
|
||||
void RenderContextImpl::FillShape(const Shape& shape)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
if (shape.IsValid())
|
||||
{
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(shape);
|
||||
render_target_->FillGeometry(geometry.Get(), brush.Get());
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(shape);
|
||||
render_ctx_->FillGeometry(geometry.Get(), brush.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -256,56 +288,40 @@ void RenderContextImpl::FillShape(const Shape& shape)
|
|||
|
||||
void RenderContextImpl::FillRectangle(const Rect& rect)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
render_target_->FillRectangle(DX::ConvertToRectF(rect), brush.Get());
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
render_ctx_->FillRectangle(DX::ConvertToRectF(rect), brush.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
||||
void RenderContextImpl::FillRoundedRectangle(const Rect& rect, const Vec2& radius)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get());
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
render_ctx_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y), brush.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
||||
void RenderContextImpl::FillEllipse(const Point& center, const Vec2& radius)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
auto brush = NativePtr::Get<ID2D1Brush>(current_brush_);
|
||||
render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get());
|
||||
auto brush = ComPolicy::Get<ID2D1Brush>(current_brush_);
|
||||
render_ctx_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y), brush.Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
||||
void RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T<uint32_t> size)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
|
||||
ComPtr<ID2D1Bitmap> saved_bitmap;
|
||||
|
||||
HRESULT hr = render_target_->CreateBitmap(D2D1::SizeU(size.x, size.y), D2D1::BitmapProperties(), &saved_bitmap);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(texture, saved_bitmap);
|
||||
}
|
||||
|
||||
KGE_THROW_IF_FAILED(hr, "Create texture failed");
|
||||
}
|
||||
|
||||
void RenderContextImpl::PushClipRect(const Rect& clip_rect)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
D2D1_ANTIALIAS_MODE mode;
|
||||
if (antialias_)
|
||||
|
|
@ -316,29 +332,29 @@ void RenderContextImpl::PushClipRect(const Rect& clip_rect)
|
|||
{
|
||||
mode = D2D1_ANTIALIAS_MODE_ALIASED;
|
||||
}
|
||||
render_target_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect), mode);
|
||||
render_ctx_->PushAxisAlignedClip(DX::ConvertToRectF(clip_rect), mode);
|
||||
}
|
||||
|
||||
void RenderContextImpl::PopClipRect()
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
render_target_->PopAxisAlignedClip();
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
render_ctx_->PopAxisAlignedClip();
|
||||
}
|
||||
|
||||
void RenderContextImpl::PushLayer(Layer& layer)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
auto native = NativePtr::Get<ID2D1Layer>(layer);
|
||||
auto mask = NativePtr::Get<ID2D1Geometry>(layer.GetMaskShape());
|
||||
auto native = ComPolicy::Get<ID2D1Layer>(layer);
|
||||
auto mask = ComPolicy::Get<ID2D1Geometry>(layer.GetMaskShape());
|
||||
|
||||
if (!native)
|
||||
{
|
||||
HRESULT hr = render_target_->CreateLayer(&native);
|
||||
HRESULT hr = render_ctx_->CreateLayer(&native);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(layer, native);
|
||||
ComPolicy::Set(layer, native);
|
||||
}
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
|
||||
}
|
||||
|
|
@ -348,32 +364,32 @@ void RenderContextImpl::PushLayer(Layer& layer)
|
|||
DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
|
||||
D2D1_LAYER_OPTIONS_NONE);
|
||||
|
||||
render_target_->PushLayer(params, native.Get());
|
||||
render_ctx_->PushLayer(params, native.Get());
|
||||
}
|
||||
|
||||
void RenderContextImpl::PopLayer()
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
render_target_->PopLayer();
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
render_ctx_->PopLayer();
|
||||
}
|
||||
|
||||
void RenderContextImpl::Clear()
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
render_target_->Clear();
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
render_ctx_->Clear();
|
||||
}
|
||||
|
||||
void RenderContextImpl::Clear(const Color& clear_color)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
render_target_->Clear(DX::ConvertToColorF(clear_color));
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
render_ctx_->Clear(DX::ConvertToColorF(clear_color));
|
||||
}
|
||||
|
||||
Size RenderContextImpl::GetSize() const
|
||||
{
|
||||
if (render_target_)
|
||||
if (render_ctx_)
|
||||
{
|
||||
return reinterpret_cast<const Size&>(render_target_->GetSize());
|
||||
return reinterpret_cast<const Size&>(render_ctx_->GetSize());
|
||||
}
|
||||
return Size();
|
||||
}
|
||||
|
|
@ -384,7 +400,7 @@ void RenderContextImpl::SetCurrentBrush(BrushPtr brush)
|
|||
|
||||
if (current_brush_ && current_brush_->IsValid())
|
||||
{
|
||||
NativePtr::Get<ID2D1Brush>(current_brush_)->SetOpacity(brush_opacity_);
|
||||
ComPolicy::Get<ID2D1Brush>(current_brush_)->SetOpacity(brush_opacity_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,30 +416,36 @@ void RenderContextImpl::SetCurrentStrokeStyle(StrokeStylePtr stroke_style)
|
|||
|
||||
void RenderContextImpl::SetTransform(const Matrix3x2& matrix)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
if (fast_global_transform_)
|
||||
{
|
||||
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
|
||||
render_ctx_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix3x2 result = matrix * global_transform_;
|
||||
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result));
|
||||
render_ctx_->SetTransform(DX::ConvertToMatrix3x2F(&result));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderContextImpl::SetBlendMode(BlendMode blend)
|
||||
{
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
render_ctx_->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND(blend));
|
||||
}
|
||||
|
||||
void RenderContextImpl::SetAntialiasMode(bool enabled)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
render_target_->SetAntialiasMode(enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
render_ctx_->SetAntialiasMode(enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
antialias_ = enabled;
|
||||
}
|
||||
|
||||
void RenderContextImpl::SetTextAntialiasMode(TextAntialiasMode mode)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||
switch (mode)
|
||||
|
|
@ -445,12 +467,12 @@ void RenderContextImpl::SetTextAntialiasMode(TextAntialiasMode mode)
|
|||
}
|
||||
|
||||
text_antialias_ = mode;
|
||||
render_target_->SetTextAntialiasMode(antialias_mode);
|
||||
render_ctx_->SetTextAntialiasMode(antialias_mode);
|
||||
}
|
||||
|
||||
bool RenderContextImpl::CheckVisibility(const Rect& bounds, const Matrix3x2& transform)
|
||||
{
|
||||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(render_ctx_ && "Render target has not been initialized!");
|
||||
|
||||
if (fast_global_transform_)
|
||||
{
|
||||
|
|
@ -470,7 +492,7 @@ void RenderContextImpl::SaveDrawingState()
|
|||
|
||||
if (drawing_state_)
|
||||
{
|
||||
render_target_->SaveDrawingState(drawing_state_.Get());
|
||||
render_ctx_->SaveDrawingState(drawing_state_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -480,8 +502,10 @@ void RenderContextImpl::RestoreDrawingState()
|
|||
|
||||
if (drawing_state_)
|
||||
{
|
||||
render_target_->RestoreDrawingState(drawing_state_.Get());
|
||||
render_ctx_->RestoreDrawingState(drawing_state_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
KGE_DECLARE_SMART_PTR(RenderContextImpl);
|
||||
|
||||
class KGE_API RenderContextImpl : public RenderContext
|
||||
|
|
@ -34,12 +37,14 @@ public:
|
|||
|
||||
virtual ~RenderContextImpl();
|
||||
|
||||
HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1RenderTarget> render_target);
|
||||
HRESULT CreateDeviceResources(ComPtr<ID2D1Factory> factory, ComPtr<ID2D1DeviceContext> ctx);
|
||||
|
||||
void BeginDraw() override;
|
||||
|
||||
void EndDraw() override;
|
||||
|
||||
void CreateTexture(Texture& texture, const PixelSize& size) override;
|
||||
|
||||
void DrawTexture(const Texture& texture, const Rect* src_rect, const Rect* dest_rect) override;
|
||||
|
||||
void DrawTextLayout(const TextLayout& layout, const Point& offset, BrushPtr outline_brush) override;
|
||||
|
|
@ -62,8 +67,6 @@ public:
|
|||
|
||||
void FillEllipse(const Point& center, const Vec2& radius) override;
|
||||
|
||||
void CreateTexture(Texture& texture, math::Vec2T<uint32_t> size) override;
|
||||
|
||||
void PushClipRect(const Rect& clip_rect) override;
|
||||
|
||||
void PopClipRect() override;
|
||||
|
|
@ -84,6 +87,8 @@ public:
|
|||
|
||||
void SetTransform(const Matrix3x2& matrix) override;
|
||||
|
||||
void SetBlendMode(BlendMode blend) override;
|
||||
|
||||
void SetAntialiasMode(bool enabled) override;
|
||||
|
||||
void SetTextAntialiasMode(TextAntialiasMode mode) override;
|
||||
|
|
@ -92,6 +97,8 @@ public:
|
|||
|
||||
void Resize(const Size& size) override;
|
||||
|
||||
TexturePtr GetTarget() const override;
|
||||
|
||||
private:
|
||||
void DiscardDeviceResources();
|
||||
|
||||
|
|
@ -101,8 +108,10 @@ private:
|
|||
|
||||
private:
|
||||
ComPtr<ITextRenderer> text_renderer_;
|
||||
ComPtr<ID2D1RenderTarget> render_target_;
|
||||
ComPtr<ID2D1DeviceContext> render_ctx_;
|
||||
ComPtr<ID2D1DrawingStateBlock> drawing_state_;
|
||||
};
|
||||
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@
|
|||
|
||||
#include <kiwano/utils/Logger.h>
|
||||
#include <kiwano/event/Events.h>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
#include <kiwano/platform/FileSystem.h>
|
||||
#include <kiwano/platform/Application.h>
|
||||
#include <kiwano/render/ShapeMaker.h>
|
||||
#include <kiwano/render/DirectX/RendererImpl.h>
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
|
||||
#define KGE_SET_STATUS_IF_FAILED(ERRCODE, OBJ, MESSAGE) \
|
||||
if (FAILED(ERRCODE)) \
|
||||
|
|
@ -37,24 +37,24 @@ namespace kiwano
|
|||
|
||||
using namespace kiwano::graphics::directx;
|
||||
|
||||
inline const GUID& ConvertPixelFormat(PixelFormat format, UINT& stride)
|
||||
inline DXGI_FORMAT ConvertPixelFormat(PixelFormat format, UINT32& pitch)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat::Bpp32RGB:
|
||||
stride = 3;
|
||||
return GUID_WICPixelFormat32bppRGB;
|
||||
//case PixelFormat::Bpp32RGB:
|
||||
// pitch = 4;
|
||||
// return DXGI_FORMAT_R8G8B8X8_UNORM;
|
||||
case PixelFormat::Bpp32RGBA:
|
||||
stride = 4;
|
||||
return GUID_WICPixelFormat32bppRGBA;
|
||||
pitch = 4;
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case PixelFormat::Bpp32BGR:
|
||||
stride = 3;
|
||||
return GUID_WICPixelFormat32bppBGR;
|
||||
pitch = 4;
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
case PixelFormat::Bpp32BGRA:
|
||||
stride = 4;
|
||||
return GUID_WICPixelFormat32bppBGRA;
|
||||
pitch = 4;
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
default:
|
||||
return GUID_WICPixelFormatDontCare;
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +258,7 @@ void RendererImpl::CreateTexture(Texture& texture, const String& file_path)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(texture, bitmap);
|
||||
ComPolicy::Set(texture, bitmap);
|
||||
|
||||
texture.SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
|
||||
texture.SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
|
||||
|
|
@ -307,7 +307,7 @@ void RendererImpl::CreateTexture(Texture& texture, const BinaryData& data)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(texture, bitmap);
|
||||
ComPolicy::Set(texture, bitmap);
|
||||
|
||||
texture.SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
|
||||
texture.SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
|
||||
|
|
@ -335,34 +335,19 @@ void RendererImpl::CreateTexture(Texture& texture, const PixelSize& size, const
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
UINT stride = 0;
|
||||
const auto& wicFormat = ConvertPixelFormat(format, stride);
|
||||
|
||||
ComPtr<IWICBitmapSource> source;
|
||||
hr = d2d_res_->CreateBitmapSourceFromMemory(source, UINT(size.x), UINT(size.y), UINT(size.x) * stride,
|
||||
UINT(data.size), reinterpret_cast<BYTE*>(data.buffer),
|
||||
wicFormat);
|
||||
ComPtr<ID2D1Bitmap1> output;
|
||||
UINT32 pitch = 0;
|
||||
const auto dxgi_format = ConvertPixelFormat(format, pitch);
|
||||
|
||||
hr = d2d_res_->GetDeviceContext()->CreateBitmap(
|
||||
DX::ConvertToSizeU(size), data.buffer, UINT(size.x) * pitch,
|
||||
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET, D2D1::PixelFormat(dxgi_format)), &output);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<IWICFormatConverter> converter;
|
||||
hr = d2d_res_->CreateBitmapConverter(converter, source, GUID_WICPixelFormat32bppPBGRA,
|
||||
WICBitmapDitherTypeNone, nullptr, 0.f,
|
||||
WICBitmapPaletteTypeMedianCut);
|
||||
ComPolicy::Set(texture, output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1Bitmap> bitmap;
|
||||
hr = d2d_res_->CreateBitmapFromConverter(bitmap, nullptr, converter);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(texture, bitmap);
|
||||
|
||||
texture.SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
|
||||
texture.SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
|
||||
}
|
||||
}
|
||||
texture.SetSize({ output->GetSize().width, output->GetSize().height });
|
||||
texture.SetSizeInPixels({ output->GetPixelSize().width, output->GetPixelSize().height });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -395,7 +380,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const String& file_path)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(gif, decoder);
|
||||
ComPolicy::Set(gif, decoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +406,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const BinaryData& data)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(gif, decoder);
|
||||
ComPolicy::Set(gif, decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -437,7 +422,7 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, const GifImage& g
|
|||
hr = E_UNEXPECTED;
|
||||
}
|
||||
|
||||
auto decoder = NativePtr::Get<IWICBitmapDecoder>(gif);
|
||||
auto decoder = ComPolicy::Get<IWICBitmapDecoder>(gif);
|
||||
|
||||
if (!decoder)
|
||||
{
|
||||
|
|
@ -464,7 +449,7 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, const GifImage& g
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
frame.texture = MakePtr<Texture>();
|
||||
NativePtr::Set(frame.texture, bitmap);
|
||||
ComPolicy::Set(frame.texture, bitmap);
|
||||
|
||||
frame.texture->SetSize({ bitmap->GetSize().width, bitmap->GetSize().height });
|
||||
frame.texture->SetSizeInPixels({ bitmap->GetPixelSize().width, bitmap->GetPixelSize().height });
|
||||
|
|
@ -618,7 +603,7 @@ void RendererImpl::CreateFontCollection(Font& font, Vector<String>& family_names
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
d2d_res_->GetFontFamilyNames(family_names, font_collection); // ignore the result
|
||||
NativePtr::Set(font, font_collection);
|
||||
ComPolicy::Set(font, font_collection);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -641,7 +626,7 @@ void RendererImpl::CreateFontCollection(Font& font, Vector<String>& family_names
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
d2d_res_->GetFontFamilyNames(family_names, font_collection); // ignore the result
|
||||
NativePtr::Set(font, font_collection);
|
||||
ComPolicy::Set(font, font_collection);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -675,7 +660,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
|
|||
auto font_weight = DWRITE_FONT_WEIGHT(font->GetWeight());
|
||||
auto font_style = DWRITE_FONT_STYLE(font->GetPosture());
|
||||
auto font_stretch = DWRITE_FONT_STRETCH(font->GetStretch());
|
||||
auto collection = NativePtr::Get<IDWriteFontCollection>(font);
|
||||
auto collection = ComPolicy::Get<IDWriteFontCollection>(font);
|
||||
|
||||
WideString font_family;
|
||||
|
||||
|
|
@ -698,7 +683,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(layout, output);
|
||||
ComPolicy::Set(layout, output);
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty);
|
||||
}
|
||||
}
|
||||
|
|
@ -735,7 +720,7 @@ void RendererImpl::CreateLineShape(Shape& shape, const Point& begin_pos, const P
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(shape, path_geo);
|
||||
ComPolicy::Set(shape, path_geo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -759,7 +744,7 @@ void RendererImpl::CreateRectShape(Shape& shape, const Rect& rect)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(shape, output);
|
||||
ComPolicy::Set(shape, output);
|
||||
}
|
||||
|
||||
KGE_SET_STATUS_IF_FAILED(hr, shape, "Create ID2D1RectangleGeometry failed");
|
||||
|
|
@ -782,7 +767,7 @@ void RendererImpl::CreateRoundedRectShape(Shape& shape, const Rect& rect, const
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(shape, output);
|
||||
ComPolicy::Set(shape, output);
|
||||
}
|
||||
|
||||
KGE_SET_STATUS_IF_FAILED(hr, shape, "Create ID2D1RoundedRectangleGeometry failed");
|
||||
|
|
@ -805,7 +790,7 @@ void RendererImpl::CreateEllipseShape(Shape& shape, const Point& center, const V
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(shape, output);
|
||||
ComPolicy::Set(shape, output);
|
||||
}
|
||||
|
||||
KGE_SET_STATUS_IF_FAILED(hr, shape, "Create ID2D1EllipseGeometry failed");
|
||||
|
|
@ -828,7 +813,7 @@ void RendererImpl::CreateShapeSink(ShapeMaker& maker)
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ShapePtr shape = MakePtr<Shape>();
|
||||
NativePtr::Set(shape, geometry);
|
||||
ComPolicy::Set(shape, geometry);
|
||||
|
||||
maker.SetShape(shape);
|
||||
}
|
||||
|
|
@ -850,7 +835,7 @@ void RendererImpl::CreateBrush(Brush& brush, const Color& color)
|
|||
|
||||
if (brush.GetType() == Brush::Type::SolidColor && brush.IsValid())
|
||||
{
|
||||
hr = NativePtr::Get<ID2D1Brush>(brush)->QueryInterface(&solid_brush);
|
||||
hr = ComPolicy::Get<ID2D1Brush>(brush)->QueryInterface(&solid_brush);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
solid_brush->SetColor(DX::ConvertToColorF(color));
|
||||
|
|
@ -862,7 +847,7 @@ void RendererImpl::CreateBrush(Brush& brush, const Color& color)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(brush, solid_brush);
|
||||
ComPolicy::Set(brush, solid_brush);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -894,7 +879,7 @@ void RendererImpl::CreateBrush(Brush& brush, const LinearGradientStyle& style)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(brush, output);
|
||||
ComPolicy::Set(brush, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -927,7 +912,7 @@ void RendererImpl::CreateBrush(Brush& brush, const RadialGradientStyle& style)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(brush, output);
|
||||
ComPolicy::Set(brush, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -945,7 +930,7 @@ void RendererImpl::CreateBrush(Brush& brush, TexturePtr texture)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto bitmap = NativePtr::Get<ID2D1Bitmap>(texture);
|
||||
auto bitmap = ComPolicy::Get<ID2D1Bitmap>(texture);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -954,7 +939,7 @@ void RendererImpl::CreateBrush(Brush& brush, TexturePtr texture)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(brush, output);
|
||||
ComPolicy::Set(brush, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -994,55 +979,60 @@ void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(stroke_style, output);
|
||||
ComPolicy::Set(stroke_style, output);
|
||||
}
|
||||
}
|
||||
|
||||
KGE_SET_STATUS_IF_FAILED(hr, stroke_style, "Create ID2D1StrokeStyle failed");
|
||||
}
|
||||
|
||||
RenderContextPtr RendererImpl::CreateTextureRenderContext(Texture& texture, const Size* desired_size)
|
||||
RenderContextPtr RendererImpl::CreateTextureRenderContext(TexturePtr texture, const PixelSize& desired_size)
|
||||
{
|
||||
RenderContextImplPtr ptr = MakePtr<RenderContextImpl>();
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
if (!d2d_res_)
|
||||
{
|
||||
hr = E_UNEXPECTED;
|
||||
}
|
||||
else if (texture == nullptr)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1BitmapRenderTarget> bitmap_rt;
|
||||
RenderContextImplPtr ptr = MakePtr<RenderContextImpl>();
|
||||
|
||||
if (desired_size)
|
||||
ComPtr<ID2D1DeviceContext> render_ctx;
|
||||
hr = d2d_res_->GetDevice()->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
|
||||
&render_ctx);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(DX::ConvertToSizeF(*desired_size),
|
||||
&bitmap_rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(&bitmap_rt);
|
||||
hr = ptr->CreateDeviceResources(d2d_res_->GetFactory(), render_ctx);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = ptr->CreateDeviceResources(d2d_res_->GetFactory(), bitmap_rt);
|
||||
}
|
||||
ComPtr<ID2D1Bitmap1> output;
|
||||
hr = render_ctx->CreateBitmap(
|
||||
DX::ConvertToSizeU(desired_size), nullptr, 0,
|
||||
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET,
|
||||
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
|
||||
&output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1Bitmap> output;
|
||||
hr = bitmap_rt->GetBitmap(&output);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(texture, output);
|
||||
render_ctx->SetTarget(output.Get());
|
||||
ComPolicy::Set(texture, output);
|
||||
|
||||
texture->SetSize({ output->GetSize().width, output->GetSize().height });
|
||||
texture->SetSizeInPixels({ output->GetPixelSize().width, output->GetPixelSize().height });
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
return ptr;
|
||||
KGE_THROW_IF_FAILED(hr, "Create render context failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1056,7 +1046,7 @@ void RendererImpl::Resize(uint32_t width, uint32_t height)
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Clear resources
|
||||
d2d_res_->SetTargetBitmap(nullptr);
|
||||
d2d_res_->GetDeviceContext()->SetTarget(nullptr);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public:
|
|||
|
||||
void CreateTexture(Texture& texture, const BinaryData& data) override;
|
||||
|
||||
void CreateTexture(Texture& texture, const PixelSize& size, const BinaryData& data, PixelFormat format);
|
||||
void CreateTexture(Texture& texture, const PixelSize& size, const BinaryData& data, PixelFormat format) override;
|
||||
|
||||
void CreateGifImage(GifImage& gif, const String& file_path) override;
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ public:
|
|||
|
||||
void CreateStrokeStyle(StrokeStyle& stroke_style) override;
|
||||
|
||||
RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) override;
|
||||
RenderContextPtr CreateTextureRenderContext(TexturePtr texture, const PixelSize& desired_size) override;
|
||||
|
||||
public:
|
||||
void Clear() override;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
class TextDrawingEffect : public ITextDrawingEffect
|
||||
{
|
||||
public:
|
||||
|
|
@ -33,17 +37,25 @@ public:
|
|||
STDMETHOD(CreateOutlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppOutlineGeo, _In_ DWRITE_GLYPH_RUN const* glyphRun, float fOriginX, float fOriginY);
|
||||
|
||||
STDMETHOD(CreateStrikethroughGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppStrikethroughGeo, _In_ DWRITE_STRIKETHROUGH const* strikethrough, float fOriginX,
|
||||
float fOriginY);
|
||||
|
||||
STDMETHOD(CreateUnderlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppUnderlineGeo, _In_ DWRITE_UNDERLINE const* underline, float fOriginX, float fOriginY);
|
||||
|
||||
// IUnknown methods
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
virtual ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
private:
|
||||
unsigned long cRefCount_;
|
||||
ComPtr<ID2D1Factory> pFactory_;
|
||||
unsigned long cRefCount_;
|
||||
ComPtr<ID2D1Factory> pFactory_;
|
||||
|
||||
// Outline geometry cache
|
||||
Map<std::tuple<const DWRITE_GLYPH_RUN*, float, float>, ComPtr<ID2D1Geometry>> outlineCache_;
|
||||
Map<std::tuple<const DWRITE_GLYPH_RUN*, float, float>, ComPtr<ID2D1Geometry>> outlineCache_;
|
||||
Map<std::tuple<const DWRITE_STRIKETHROUGH*, float, float>, ComPtr<ID2D1Geometry>> strikethroughCache_;
|
||||
Map<std::tuple<const DWRITE_UNDERLINE*, float, float>, ComPtr<ID2D1Geometry>> underlineCache_;
|
||||
};
|
||||
|
||||
HRESULT ITextDrawingEffect::Create(_Out_ ITextDrawingEffect** ppTextDrawingEffect, _In_ ID2D1Factory* pFactory)
|
||||
|
|
@ -156,6 +168,115 @@ STDMETHODIMP TextDrawingEffect::CreateOutlineGeomerty(_Out_ ID2D1Geometry**
|
|||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP TextDrawingEffect::CreateStrikethroughGeomerty(_Out_ ID2D1Geometry** ppStrikethroughGeo,
|
||||
_In_ DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
float fOriginX, float fOriginY)
|
||||
{
|
||||
auto cache = strikethroughCache_.find(std::make_tuple(strikethrough, fOriginX, fOriginY));
|
||||
if (cache != strikethroughCache_.end())
|
||||
{
|
||||
auto& pStrikethroughGeo = cache->second;
|
||||
if (pStrikethroughGeo)
|
||||
{
|
||||
// Use cached geometry
|
||||
pStrikethroughGeo->AddRef();
|
||||
DX::SafeRelease(*ppStrikethroughGeo);
|
||||
(*ppStrikethroughGeo) = pStrikethroughGeo.Get();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1Geometry> pStrikethroughGeo;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
|
||||
D2D1_RECT_F rect = D2D1::RectF(0, strikethrough->offset, strikethrough->width,
|
||||
strikethrough->offset + strikethrough->thickness);
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
const auto matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, fOriginX, fOriginY);
|
||||
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pStrikethroughGeo = pTransformedGeometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pStrikethroughGeo->AddRef();
|
||||
DX::SafeRelease(*ppStrikethroughGeo);
|
||||
(*ppStrikethroughGeo) = pStrikethroughGeo.Get();
|
||||
|
||||
strikethroughCache_.insert(
|
||||
std::make_pair(std::make_tuple(strikethrough, fOriginX, fOriginY), pStrikethroughGeo));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP TextDrawingEffect::CreateUnderlineGeomerty(_Out_ ID2D1Geometry** ppUnderlineGeo,
|
||||
_In_ DWRITE_UNDERLINE const* underline, float fOriginX,
|
||||
float fOriginY)
|
||||
{
|
||||
auto cache = underlineCache_.find(std::make_tuple(underline, fOriginX, fOriginY));
|
||||
if (cache != underlineCache_.end())
|
||||
{
|
||||
auto& pUnderlineGeo = cache->second;
|
||||
if (pUnderlineGeo)
|
||||
{
|
||||
// Use cached geometry
|
||||
pUnderlineGeo->AddRef();
|
||||
DX::SafeRelease(*ppUnderlineGeo);
|
||||
(*ppUnderlineGeo) = pUnderlineGeo.Get();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1Geometry> pUnderlineGeo;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
|
||||
D2D1_RECT_F rect =
|
||||
D2D1::RectF(0, underline->offset, underline->width, underline->offset + underline->thickness);
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
const auto matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, fOriginX, fOriginY);
|
||||
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pUnderlineGeo = pTransformedGeometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pUnderlineGeo->AddRef();
|
||||
DX::SafeRelease(*ppUnderlineGeo);
|
||||
(*ppUnderlineGeo) = pUnderlineGeo.Get();
|
||||
|
||||
underlineCache_.insert(std::make_pair(std::make_tuple(underline, fOriginX, fOriginY), pUnderlineGeo));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(unsigned long) TextDrawingEffect::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&cRefCount_);
|
||||
|
|
@ -194,4 +315,6 @@ STDMETHODIMP TextDrawingEffect::QueryInterface(REFIID riid, void** ppvObject)
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -24,13 +24,26 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
interface DWRITE_DECLARE_INTERFACE("7431F439-6E54-4707-A0DC-1AA035D6AFB8") ITextDrawingEffect : public IUnknown
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
interface DWRITE_DECLARE_INTERFACE("7431F439-6E54-4707-A0DC-1AA035D6AFB8") ITextDrawingEffect
|
||||
: public IUnknown
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(_Out_ ITextDrawingEffect** ppTextDrawingEffect, _In_ ID2D1Factory* pFactory);
|
||||
|
||||
STDMETHOD(CreateOutlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppOutlineGeo, _In_ DWRITE_GLYPH_RUN const* glyphRun, float fOriginX, float fOriginY) PURE;
|
||||
|
||||
STDMETHOD(CreateStrikethroughGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppStrikethroughGeo, _In_ DWRITE_STRIKETHROUGH const* strikethrough, float fOriginX,
|
||||
float fOriginY) PURE;
|
||||
|
||||
STDMETHOD(CreateUnderlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppUnderlineGeo, _In_ DWRITE_UNDERLINE const* underline, float fOriginX, float fOriginY) PURE;
|
||||
};
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
class TextRenderer : public ITextRenderer
|
||||
{
|
||||
public:
|
||||
|
|
@ -30,7 +34,7 @@ public:
|
|||
|
||||
~TextRenderer();
|
||||
|
||||
STDMETHOD(CreateDeviceResources)(_In_ ID2D1RenderTarget* pRT);
|
||||
STDMETHOD(CreateDeviceResources)(_In_ ID2D1DeviceContext* pContext);
|
||||
|
||||
STDMETHOD(DrawTextLayout)
|
||||
(_In_ IDWriteTextLayout* pTextLayout, float fOriginX, float fOriginY, _In_opt_ ID2D1Brush* pDefaultFillBrush,
|
||||
|
|
@ -67,17 +71,18 @@ public:
|
|||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
private:
|
||||
unsigned long cRefCount_;
|
||||
uint32_t cPrimitivesCount_;
|
||||
float fDefaultOutlineWidth_;
|
||||
ComPtr<ID2D1Factory> pFactory_;
|
||||
ComPtr<ID2D1RenderTarget> pRT_;
|
||||
ComPtr<ID2D1Brush> pDefaultFillBrush_;
|
||||
ComPtr<ID2D1Brush> pDefaultOutlineBrush_;
|
||||
ComPtr<ID2D1StrokeStyle> pDefaultStrokeStyle_;
|
||||
bool bOutlineRendering_;
|
||||
unsigned long cRefCount_;
|
||||
uint32_t cPrimitivesCount_;
|
||||
float fDefaultOutlineWidth_;
|
||||
ComPtr<ID2D1Factory> pFactory_;
|
||||
ComPtr<ID2D1DeviceContext> pContext_;
|
||||
ComPtr<ID2D1Brush> pDefaultFillBrush_;
|
||||
ComPtr<ID2D1Brush> pDefaultOutlineBrush_;
|
||||
ComPtr<ID2D1StrokeStyle> pDefaultStrokeStyle_;
|
||||
};
|
||||
|
||||
HRESULT ITextRenderer::Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1RenderTarget* pRT)
|
||||
HRESULT ITextRenderer::Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1DeviceContext* pContext)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
|
|
@ -86,7 +91,7 @@ HRESULT ITextRenderer::Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1Re
|
|||
TextRenderer* pTextRenderer = new (std::nothrow) TextRenderer;
|
||||
if (pTextRenderer)
|
||||
{
|
||||
hr = pTextRenderer->CreateDeviceResources(pRT);
|
||||
hr = pTextRenderer->CreateDeviceResources(pContext);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -107,7 +112,8 @@ HRESULT ITextRenderer::Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1Re
|
|||
}
|
||||
|
||||
TextRenderer::TextRenderer()
|
||||
: cRefCount_(0)
|
||||
: bOutlineRendering_(false)
|
||||
, cRefCount_(0)
|
||||
, cPrimitivesCount_(0)
|
||||
, fDefaultOutlineWidth_(1)
|
||||
{
|
||||
|
|
@ -115,17 +121,17 @@ TextRenderer::TextRenderer()
|
|||
|
||||
TextRenderer::~TextRenderer() {}
|
||||
|
||||
STDMETHODIMP TextRenderer::CreateDeviceResources(_In_ ID2D1RenderTarget* pRT)
|
||||
STDMETHODIMP TextRenderer::CreateDeviceResources(_In_ ID2D1DeviceContext* pContext)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
pFactory_.Reset();
|
||||
pRT_.Reset();
|
||||
pContext_.Reset();
|
||||
|
||||
if (pRT)
|
||||
if (pContext)
|
||||
{
|
||||
pRT_ = pRT;
|
||||
pRT_->GetFactory(&pFactory_);
|
||||
pContext_ = pContext;
|
||||
pContext_->GetFactory(&pFactory_);
|
||||
hr = S_OK;
|
||||
}
|
||||
return hr;
|
||||
|
|
@ -146,13 +152,21 @@ STDMETHODIMP TextRenderer::DrawTextLayout(_In_ IDWriteTextLayout* pTextLayout, f
|
|||
pDefaultOutlineBrush_ = pDefaultOutlineBrush;
|
||||
fDefaultOutlineWidth_ = fDefaultOutlineWidth;
|
||||
pDefaultStrokeStyle_ = pDefaultStrokeStyle;
|
||||
bOutlineRendering_ = pDefaultOutlineBrush_ != nullptr;
|
||||
|
||||
return pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
|
||||
HRESULT hr = pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
|
||||
if (SUCCEEDED(hr) && bOutlineRendering_)
|
||||
{
|
||||
bOutlineRendering_ = false;
|
||||
|
||||
hr = pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext, float baselineOriginX,
|
||||
float baselineOriginY, DWRITE_MEASURING_MODE measuringMode,
|
||||
__in DWRITE_GLYPH_RUN const* glyphRun,
|
||||
__in DWRITE_GLYPH_RUN const* glyphRun,
|
||||
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
IUnknown* clientDrawingEffect)
|
||||
{
|
||||
|
|
@ -160,36 +174,41 @@ STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext,
|
|||
KGE_NOT_USED(measuringMode);
|
||||
KGE_NOT_USED(glyphRunDescription);
|
||||
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
|
||||
HRESULT hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
if (pDefaultOutlineBrush_)
|
||||
HRESULT hr = S_OK;
|
||||
if (!bOutlineRendering_)
|
||||
{
|
||||
ComPtr<ID2D1Geometry> pOutlineGeometry;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (pDefaultFillBrush_)
|
||||
{
|
||||
hr = pTextDrawingEffect->CreateOutlineGeomerty(&pOutlineGeometry, glyphRun, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pContext_->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun,
|
||||
pDefaultFillBrush_.Get());
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pRT_->DrawGeometry(pOutlineGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pDefaultFillBrush_)
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
if (pDefaultOutlineBrush_)
|
||||
{
|
||||
pRT_->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun, pDefaultFillBrush_.Get());
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
++cPrimitivesCount_;
|
||||
ComPtr<ID2D1Geometry> pOutlineGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pTextDrawingEffect->CreateOutlineGeomerty(&pOutlineGeometry, glyphRun, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pContext_->DrawGeometry(pOutlineGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
|
|
@ -203,51 +222,37 @@ STDMETHODIMP TextRenderer::DrawUnderline(__maybenull void* clientDrawingContext,
|
|||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
ComPtr<ID2D1Brush> pCurrentFillBrush;
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
if (clientDrawingEffect)
|
||||
ComPtr<ID2D1Geometry> pUnderlineGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = clientDrawingEffect->QueryInterface<ID2D1Brush>(&pCurrentFillBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
pCurrentFillBrush = pDefaultFillBrush_;
|
||||
hr = pTextDrawingEffect->CreateUnderlineGeomerty(&pUnderlineGeometry, underline, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
|
||||
if (pCurrentFillBrush || pDefaultOutlineBrush_)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
if (!bOutlineRendering_)
|
||||
{
|
||||
D2D1_RECT_F rect =
|
||||
D2D1::RectF(0, underline->offset, underline->width, underline->offset + underline->thickness);
|
||||
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
if (pDefaultFillBrush_)
|
||||
{
|
||||
pContext_->FillGeometry(pUnderlineGeometry.Get(), pDefaultFillBrush_.Get());
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
else
|
||||
{
|
||||
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY);
|
||||
if (pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGeometry(pUnderlineGeometry.Get(), pDefaultOutlineBrush_.Get(),
|
||||
fDefaultOutlineWidth_, pDefaultStrokeStyle_.Get());
|
||||
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pDefaultOutlineBrush_)
|
||||
{
|
||||
pRT_->DrawGeometry(pTransformedGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pCurrentFillBrush)
|
||||
{
|
||||
pRT_->FillGeometry(pTransformedGeometry.Get(), pCurrentFillBrush.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
@ -259,51 +264,37 @@ STDMETHODIMP TextRenderer::DrawStrikethrough(__maybenull void* clientDrawingCont
|
|||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
ComPtr<ID2D1Brush> pCurrentFillBrush;
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
if (clientDrawingEffect)
|
||||
ComPtr<ID2D1Geometry> pStrikethroughGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = clientDrawingEffect->QueryInterface<ID2D1Brush>(&pCurrentFillBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
pCurrentFillBrush = pDefaultFillBrush_;
|
||||
hr = pTextDrawingEffect->CreateStrikethroughGeomerty(&pStrikethroughGeometry, strikethrough, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
|
||||
if (pCurrentFillBrush || pDefaultOutlineBrush_)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
if (!bOutlineRendering_)
|
||||
{
|
||||
D2D1_RECT_F rect = D2D1::RectF(0, strikethrough->offset, strikethrough->width,
|
||||
strikethrough->offset + strikethrough->thickness);
|
||||
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
if (pDefaultFillBrush_)
|
||||
{
|
||||
pContext_->FillGeometry(pStrikethroughGeometry.Get(), pDefaultFillBrush_.Get());
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
else
|
||||
{
|
||||
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY);
|
||||
if (pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGeometry(pStrikethroughGeometry.Get(), pDefaultOutlineBrush_.Get(),
|
||||
fDefaultOutlineWidth_, pDefaultStrokeStyle_.Get());
|
||||
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pDefaultOutlineBrush_)
|
||||
{
|
||||
pRT_->DrawGeometry(pTransformedGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pCurrentFillBrush)
|
||||
{
|
||||
pRT_->FillGeometry(pTransformedGeometry.Get(), pCurrentFillBrush.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
@ -333,7 +324,7 @@ STDMETHODIMP TextRenderer::GetCurrentTransform(__maybenull void* clientDrawingCo
|
|||
{
|
||||
KGE_NOT_USED(clientDrawingContext);
|
||||
|
||||
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
|
||||
pContext_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +334,7 @@ STDMETHODIMP TextRenderer::GetPixelsPerDip(__maybenull void* clientDrawingContex
|
|||
|
||||
float x, yUnused;
|
||||
|
||||
pRT_->GetDpi(&x, &yUnused);
|
||||
pContext_->GetDpi(&x, &yUnused);
|
||||
*pixelsPerDip = x / 96;
|
||||
|
||||
return S_OK;
|
||||
|
|
@ -400,4 +391,6 @@ STDMETHODIMP TextRenderer::QueryInterface(REFIID riid, void** ppvObject)
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -23,16 +23,23 @@
|
|||
|
||||
namespace kiwano
|
||||
{
|
||||
interface DWRITE_DECLARE_INTERFACE("b293e798-9916-4096-a3c1-e5d4039dfa64") ITextRenderer : public IDWriteTextRenderer
|
||||
namespace graphics
|
||||
{
|
||||
namespace directx
|
||||
{
|
||||
interface DWRITE_DECLARE_INTERFACE("b293e798-9916-4096-a3c1-e5d4039dfa64") ITextRenderer
|
||||
: public IDWriteTextRenderer
|
||||
{
|
||||
public:
|
||||
static KGE_API HRESULT Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1RenderTarget* pRT);
|
||||
static KGE_API HRESULT Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1DeviceContext* pContext);
|
||||
|
||||
STDMETHOD(DrawTextLayout)
|
||||
(_In_ IDWriteTextLayout * pTextLayout, float fOriginX, float fOriginY, _In_opt_ ID2D1Brush* pDefaultFillBrush,
|
||||
(_In_ IDWriteTextLayout* pTextLayout, float fOriginX, float fOriginY, _In_opt_ ID2D1Brush* pDefaultFillBrush,
|
||||
_In_opt_ ID2D1Brush* pDefaultOutlineBrush, float fDefaultOutlineWidth,
|
||||
_In_opt_ ID2D1StrokeStyle* pDefaultStrokeStyle) PURE;
|
||||
|
||||
STDMETHOD_(uint32_t, GetLastPrimitivesCount)() PURE;
|
||||
};
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
#include <kiwano/utils/Logger.h>
|
||||
#include <kiwano/render/Color.h>
|
||||
#include <kiwano/platform/win32/ComPtr.hpp>
|
||||
#include <d2d1.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -76,7 +76,7 @@ inline D2D1_POINT_2F* ConvertToPoint2F(Vec2* vec2)
|
|||
}
|
||||
|
||||
//
|
||||
// SizeF
|
||||
// Size
|
||||
//
|
||||
|
||||
inline const D2D1_SIZE_F& ConvertToSizeF(const Vec2& vec2)
|
||||
|
|
@ -99,6 +99,26 @@ inline D2D1_SIZE_F* ConvertToSizeF(Vec2* vec2)
|
|||
return reinterpret_cast<D2D1_SIZE_F*>(vec2);
|
||||
}
|
||||
|
||||
inline const D2D1_SIZE_U& ConvertToSizeU(const math::Vec2T<uint32_t>& vec2)
|
||||
{
|
||||
return reinterpret_cast<const D2D1_SIZE_U&>(vec2);
|
||||
}
|
||||
|
||||
inline D2D1_SIZE_U& ConvertToSizeU(math::Vec2T<uint32_t>& vec2)
|
||||
{
|
||||
return reinterpret_cast<D2D1_SIZE_U&>(vec2);
|
||||
}
|
||||
|
||||
inline const D2D1_SIZE_U* ConvertToSizeU(const math::Vec2T<uint32_t>* vec2)
|
||||
{
|
||||
return reinterpret_cast<const D2D1_SIZE_U*>(vec2);
|
||||
}
|
||||
|
||||
inline D2D1_SIZE_U* ConvertToSizeU(math::Vec2T<uint32_t>* vec2)
|
||||
{
|
||||
return reinterpret_cast<D2D1_SIZE_U*>(vec2);
|
||||
}
|
||||
|
||||
//
|
||||
// RectF
|
||||
//
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ Font::Font(const String& family_name, float size, uint32_t weight, FontPosture p
|
|||
FontPtr found = FontCache::GetInstance().GetFontByFamily(family_name);
|
||||
if (found)
|
||||
{
|
||||
this->ResetNativePointer(found->GetNativePointer());
|
||||
this->SetNative(found->GetNative());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ bool GifImage::Load(const String& file_path)
|
|||
return true;
|
||||
|
||||
// Clear data
|
||||
ResetNativePointer();
|
||||
ResetNative();
|
||||
Fail("GifImage::Load failed");
|
||||
}
|
||||
return false;
|
||||
|
|
@ -100,7 +100,7 @@ bool GifImage::Load(const Resource& res)
|
|||
return true;
|
||||
|
||||
// Clear data
|
||||
ResetNativePointer();
|
||||
ResetNative();
|
||||
Fail("GifImage::Load failed");
|
||||
}
|
||||
return false;
|
||||
|
|
@ -116,14 +116,14 @@ GifImage::Frame GifImage::GetFrame(uint32_t index)
|
|||
} // namespace kiwano
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
bool GifImage::GetGlobalMetadata()
|
||||
{
|
||||
ComPtr<IWICBitmapDecoder> decoder = NativePtr::Get<IWICBitmapDecoder>(this);
|
||||
ComPtr<IWICBitmapDecoder> decoder = ComPolicy::Get<IWICBitmapDecoder>(this);
|
||||
|
||||
HRESULT hr = decoder ? S_OK : E_FAIL;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
#include "NativeObject.h"
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
NativeObjectBase::NativeObjectBase()
|
||||
: native_pointer_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
bool NativeObjectBase::IsValid() const
|
||||
{
|
||||
return native_pointer_ != nullptr;
|
||||
}
|
||||
|
||||
void NativeObjectBase::ResetNativePointer(void* native_pointer)
|
||||
{
|
||||
native_pointer_ = native_pointer;
|
||||
}
|
||||
|
||||
//
|
||||
// NativeObject for Windows
|
||||
//
|
||||
#if defined(KGE_PLATFORM_WINDOWS)
|
||||
|
||||
NativeObject::~NativeObject()
|
||||
{
|
||||
ResetNativePointer();
|
||||
}
|
||||
|
||||
void NativeObject::ResetNativePointer(void* native_pointer)
|
||||
{
|
||||
if (native_pointer_)
|
||||
{
|
||||
static_cast<IUnknown*>(native_pointer_)->Release();
|
||||
native_pointer_ = nullptr;
|
||||
}
|
||||
|
||||
if (native_pointer)
|
||||
{
|
||||
native_pointer_ = native_pointer;
|
||||
static_cast<IUnknown*>(native_pointer_)->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
@ -24,14 +24,9 @@
|
|||
namespace kiwano
|
||||
{
|
||||
|
||||
RenderContextPtr RenderContext::Create(Texture& texture)
|
||||
RenderContextPtr RenderContext::Create(TexturePtr texture, const PixelSize& size)
|
||||
{
|
||||
return Renderer::GetInstance().CreateTextureRenderContext(texture, nullptr);
|
||||
}
|
||||
|
||||
RenderContextPtr RenderContext::Create(Texture& texture, const Size& size)
|
||||
{
|
||||
return Renderer::GetInstance().CreateTextureRenderContext(texture, &size);
|
||||
return Renderer::GetInstance().CreateTextureRenderContext(texture, size);
|
||||
}
|
||||
|
||||
RenderContext::RenderContext()
|
||||
|
|
|
|||
|
|
@ -46,22 +46,28 @@ enum class TextAntialiasMode
|
|||
None ///< 不启用抗锯齿
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 混合模式
|
||||
enum class BlendMode
|
||||
{
|
||||
SourceOver = 0,
|
||||
Copy = 1,
|
||||
Min = 2,
|
||||
Add = 3,
|
||||
Max = 4,
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 渲染上下文
|
||||
/// @details 渲染上下文将完成基础图元的绘制,并将绘制结果输出到特定的平面中
|
||||
class KGE_API RenderContext : public NativeObject
|
||||
{
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 创建纹理渲染上下文,将绘制结果输出到纹理中
|
||||
/// @param texture 保存绘制结果的纹理
|
||||
static RenderContextPtr Create(Texture& texture);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建纹理渲染上下文,将绘制结果输出到纹理中
|
||||
/// @param texture 保存绘制结果的纹理
|
||||
/// @param size 渲染输出大小
|
||||
static RenderContextPtr Create(Texture& texture, const Size& size);
|
||||
static RenderContextPtr Create(TexturePtr texture, const PixelSize& size);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 开始渲染
|
||||
|
|
@ -71,6 +77,12 @@ public:
|
|||
/// @brief 结束渲染
|
||||
virtual void EndDraw();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建空纹理
|
||||
/// @param[out] texture 输出纹理
|
||||
/// @param[in] size 纹理像素大小
|
||||
virtual void CreateTexture(Texture& texture, const PixelSize& size) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 绘制纹理
|
||||
/// @param texture 纹理
|
||||
|
|
@ -148,12 +160,6 @@ public:
|
|||
/// @param radius 椭圆半径
|
||||
virtual void FillEllipse(const Point& center, const Vec2& radius) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建纹理
|
||||
/// @param texture 纹理
|
||||
/// @param size 纹理像素大小
|
||||
virtual void CreateTexture(Texture& texture, math::Vec2T<uint32_t> size) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置绘制的裁剪区域
|
||||
/// @param clip_rect 裁剪矩形
|
||||
|
|
@ -209,6 +215,10 @@ public:
|
|||
/// @brief 设置当前使用的线条样式
|
||||
virtual void SetCurrentStrokeStyle(StrokeStylePtr stroke);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置混合模式
|
||||
virtual void SetBlendMode(BlendMode blend) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置抗锯齿模式
|
||||
virtual void SetAntialiasMode(bool enabled) = 0;
|
||||
|
|
@ -237,6 +247,10 @@ public:
|
|||
/// @brief 设置全局二维变换
|
||||
virtual void SetGlobalTransform(const Matrix3x2* matrix);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取渲染目标
|
||||
virtual TexturePtr GetTarget() const = 0;
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 渲染上下文状态
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ public:
|
|||
/// @param[in,out] texture 渲染输出的纹理
|
||||
/// @param[in] desired_size 期望的输出大小
|
||||
/// @return 纹理渲染上下文
|
||||
virtual RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) = 0;
|
||||
virtual RenderContextPtr CreateTextureRenderContext(TexturePtr texture, const PixelSize& desired_size) = 0;
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#include <kiwano/render/Renderer.h>
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
#endif
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -33,14 +33,14 @@ Shape::Shape() {}
|
|||
|
||||
void Shape::Clear()
|
||||
{
|
||||
ResetNativePointer();
|
||||
ResetNative();
|
||||
}
|
||||
|
||||
Rect Shape::GetBoundingBox() const
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
Rect bounds;
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(this);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(this);
|
||||
if (geometry)
|
||||
{
|
||||
// no matter it failed or not
|
||||
|
|
@ -56,7 +56,7 @@ Rect Shape::GetBoundingBox(const Matrix3x2& transform) const
|
|||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
Rect bounds;
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(this);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(this);
|
||||
if (geometry)
|
||||
{
|
||||
// no matter it failed or not
|
||||
|
|
@ -72,7 +72,7 @@ float Shape::GetLength() const
|
|||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
float length = 0.f;
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(this);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(this);
|
||||
if (geometry)
|
||||
{
|
||||
// no matter it failed or not
|
||||
|
|
@ -87,7 +87,7 @@ float Shape::GetLength() const
|
|||
bool Shape::ComputePointAtLength(float length, Point& point, Vec2& tangent) const
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(this);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(this);
|
||||
if (geometry)
|
||||
{
|
||||
HRESULT hr = geometry->ComputePointAtLength(length, D2D1::Matrix3x2F::Identity(), DX::ConvertToPoint2F(&point),
|
||||
|
|
@ -104,7 +104,7 @@ bool Shape::ComputePointAtLength(float length, Point& point, Vec2& tangent) cons
|
|||
float Shape::ComputeArea() const
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(this);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(this);
|
||||
if (geometry)
|
||||
{
|
||||
float area = 0.f;
|
||||
|
|
@ -120,7 +120,7 @@ float Shape::ComputeArea() const
|
|||
bool Shape::ContainsPoint(const Point& point, const Matrix3x2* transform) const
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto geometry = NativePtr::Get<ID2D1Geometry>(this);
|
||||
auto geometry = ComPolicy::Get<ID2D1Geometry>(this);
|
||||
if (!geometry)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <kiwano/render/Renderer.h>
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
#endif
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -38,7 +38,7 @@ ShapeMaker::~ShapeMaker()
|
|||
void ShapeMaker::Clear()
|
||||
{
|
||||
CloseStream();
|
||||
ResetNativePointer();
|
||||
ResetNative();
|
||||
}
|
||||
|
||||
ShapePtr ShapeMaker::GetShape()
|
||||
|
|
@ -59,7 +59,7 @@ void ShapeMaker::BeginPath(const Point& begin_pos)
|
|||
}
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
|
||||
#else
|
||||
// not supported
|
||||
|
|
@ -71,7 +71,7 @@ void ShapeMaker::EndPath(bool closed)
|
|||
KGE_ASSERT(IsStreamOpened());
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
|
||||
#else
|
||||
// not supported
|
||||
|
|
@ -85,7 +85,7 @@ void ShapeMaker::AddLine(const Point& point)
|
|||
KGE_ASSERT(IsStreamOpened());
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->AddLine(DX::ConvertToPoint2F(point));
|
||||
#else
|
||||
// not supported
|
||||
|
|
@ -97,7 +97,7 @@ void ShapeMaker::AddLines(const Vector<Point>& points)
|
|||
KGE_ASSERT(IsStreamOpened());
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->AddLines(reinterpret_cast<const D2D_POINT_2F*>(&points[0]), static_cast<uint32_t>(points.size()));
|
||||
#else
|
||||
// not supported
|
||||
|
|
@ -109,7 +109,7 @@ void kiwano::ShapeMaker::AddLines(const Point* points, size_t count)
|
|||
KGE_ASSERT(IsStreamOpened());
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->AddLines(reinterpret_cast<const D2D_POINT_2F*>(points), UINT32(count));
|
||||
#else
|
||||
// not supported
|
||||
|
|
@ -121,7 +121,7 @@ void ShapeMaker::AddBezier(const Point& point1, const Point& point2, const Point
|
|||
KGE_ASSERT(IsStreamOpened());
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->AddBezier(
|
||||
D2D1::BezierSegment(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2), DX::ConvertToPoint2F(point3)));
|
||||
#else
|
||||
|
|
@ -134,7 +134,7 @@ void ShapeMaker::AddArc(const Point& point, const Size& radius, float rotation,
|
|||
KGE_ASSERT(IsStreamOpened());
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
native->AddArc(D2D1::ArcSegment(DX::ConvertToPoint2F(point), DX::ConvertToSizeF(radius), rotation,
|
||||
clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
|
||||
is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE));
|
||||
|
|
@ -151,9 +151,9 @@ ShapePtr ShapeMaker::Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mod
|
|||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (shape_a && shape_b)
|
||||
{
|
||||
auto geo_a = NativePtr::Get<ID2D1Geometry>(shape_a);
|
||||
auto geo_b = NativePtr::Get<ID2D1Geometry>(shape_b);
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(maker);
|
||||
auto geo_a = ComPolicy::Get<ID2D1Geometry>(shape_a);
|
||||
auto geo_b = ComPolicy::Get<ID2D1Geometry>(shape_b);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(maker);
|
||||
|
||||
HRESULT hr = geo_a->CombineWithGeometry(geo_b.Get(), D2D1_COMBINE_MODE(mode), DX::ConvertToMatrix3x2F(matrix),
|
||||
native.Get());
|
||||
|
|
@ -176,7 +176,7 @@ void ShapeMaker::OpenStream()
|
|||
Renderer::GetInstance().CreateShapeSink(*this);
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto geometry = NativePtr::Get<ID2D1PathGeometry>(shape_);
|
||||
auto geometry = ComPolicy::Get<ID2D1PathGeometry>(shape_);
|
||||
if (geometry)
|
||||
{
|
||||
ComPtr<ID2D1GeometrySink> native;
|
||||
|
|
@ -184,7 +184,7 @@ void ShapeMaker::OpenStream()
|
|||
HRESULT hr = geometry->Open(&native);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(this, native);
|
||||
ComPolicy::Set(this, native);
|
||||
}
|
||||
KGE_THROW_IF_FAILED(hr, "ID2D1PathGeometry::Open failed");
|
||||
}
|
||||
|
|
@ -199,12 +199,12 @@ void ShapeMaker::CloseStream()
|
|||
return;
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<ID2D1GeometrySink>(this);
|
||||
auto native = ComPolicy::Get<ID2D1GeometrySink>(this);
|
||||
|
||||
HRESULT hr = native->Close();
|
||||
KGE_THROW_IF_FAILED(hr, "ID2D1PathGeometry::Close failed");
|
||||
|
||||
ResetNativePointer();
|
||||
ResetNative();
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/render/Renderer.h>
|
||||
#include <kiwano/render/StrokeStyle.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <kiwano/render/TextLayout.h>
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
#endif
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -41,8 +41,13 @@ TextLayout::TextLayout(const String& content, const TextStyle& style)
|
|||
Reset(content, style);
|
||||
}
|
||||
|
||||
void TextLayout::Reset(const String& content, const TextStyle& style)
|
||||
void TextLayout::Clear()
|
||||
{
|
||||
ResetNative();
|
||||
}
|
||||
|
||||
void TextLayout::Reset(const String& content, const TextStyle& style)
|
||||
{
|
||||
content_length_ = (uint32_t)content.length();
|
||||
if (content_length_)
|
||||
{
|
||||
|
|
@ -84,7 +89,7 @@ void TextLayout::SetFont(FontPtr font)
|
|||
return;
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>((const NativeObject*)(this));
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
@ -93,7 +98,7 @@ void TextLayout::SetFont(FontPtr font)
|
|||
|
||||
// reset font collection
|
||||
{
|
||||
auto collection = NativePtr::Get<IDWriteFontCollection>(font);
|
||||
auto collection = ComPolicy::Get<IDWriteFontCollection>(font);
|
||||
|
||||
hr = native->SetFontCollection(collection.Get(), { 0, content_length_ });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontCollection failed");
|
||||
|
|
@ -148,7 +153,7 @@ void TextLayout::SetFont(FontPtr font)
|
|||
void TextLayout::SetUnderline(bool enable)
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
@ -166,7 +171,7 @@ void TextLayout::SetUnderline(bool enable)
|
|||
void TextLayout::SetStrikethrough(bool enable)
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
@ -184,7 +189,7 @@ void TextLayout::SetStrikethrough(bool enable)
|
|||
void TextLayout::SetAlignment(TextAlign align)
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
@ -219,7 +224,7 @@ void TextLayout::SetAlignment(TextAlign align)
|
|||
void TextLayout::SetWrapWidth(float wrap_width)
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
@ -249,7 +254,7 @@ void TextLayout::SetWrapWidth(float wrap_width)
|
|||
void TextLayout::SetLineSpacing(float line_spacing)
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
|
|
@ -284,7 +289,7 @@ bool TextLayout::UpdateIfDirty()
|
|||
line_count_ = 0;
|
||||
size_ = Size();
|
||||
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
auto native = ComPolicy::Get<IDWriteTextLayout>(this);
|
||||
if (content_length_ == 0 || !native)
|
||||
return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano/math/Math.h>
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
#include <kiwano/render/TextStyle.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -135,11 +135,6 @@ inline bool TextLayout::IsDirty() const
|
|||
return dirty_flag_ != DirtyFlag::Clean;
|
||||
}
|
||||
|
||||
inline void TextLayout::Clear()
|
||||
{
|
||||
ResetNativePointer();
|
||||
}
|
||||
|
||||
inline uint32_t TextLayout::GetContentLength() const
|
||||
{
|
||||
return content_length_;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <functional> // std::hash
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
#include <kiwano/render/DirectX/NativePtr.h>
|
||||
#include <kiwano/render/DirectX/helper.h>
|
||||
#endif
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -108,8 +108,8 @@ void Texture::CopyFrom(TexturePtr copy_from)
|
|||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (IsValid() && copy_from)
|
||||
{
|
||||
auto native = NativePtr::Get<ID2D1Bitmap>(this);
|
||||
auto native_to_copy = NativePtr::Get<ID2D1Bitmap>(copy_from);
|
||||
auto native = ComPolicy::Get<ID2D1Bitmap>(this);
|
||||
auto native_to_copy = ComPolicy::Get<ID2D1Bitmap>(copy_from);
|
||||
|
||||
HRESULT hr = native->CopyFromBitmap(nullptr, native_to_copy.Get(), nullptr);
|
||||
|
||||
|
|
@ -125,8 +125,8 @@ void Texture::CopyFrom(TexturePtr copy_from, const Rect& src_rect, const Point&
|
|||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (IsValid() && copy_from)
|
||||
{
|
||||
auto native = NativePtr::Get<ID2D1Bitmap>(this);
|
||||
auto native_to_copy = NativePtr::Get<ID2D1Bitmap>(copy_from);
|
||||
auto native = ComPolicy::Get<ID2D1Bitmap>(this);
|
||||
auto native_to_copy = ComPolicy::Get<ID2D1Bitmap>(copy_from);
|
||||
|
||||
HRESULT hr =
|
||||
native->CopyFromBitmap(&D2D1::Point2U(uint32_t(dest_point.x), uint32_t(dest_point.y)), native_to_copy.Get(),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#pragma once
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/render/NativeObject.h>
|
||||
#include <kiwano/platform/NativeObject.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -54,7 +54,6 @@ typedef math::Vec2T<uint32_t> PixelSize;
|
|||
*/
|
||||
enum class PixelFormat
|
||||
{
|
||||
Bpp32RGB,
|
||||
Bpp32RGBA,
|
||||
Bpp32BGR,
|
||||
Bpp32BGRA,
|
||||
|
|
|
|||
Loading…
Reference in New Issue