Component design

This commit is contained in:
Nomango 2019-03-11 17:24:11 +08:00 committed by Nomango
parent 2f4501067b
commit b1b1f0c22c
35 changed files with 722 additions and 457 deletions

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\src\audio\audio.h" />
<ClInclude Include="..\..\src\audio\audio-modules.h" />
<ClInclude Include="..\..\src\audio\Music.h" />
<ClInclude Include="..\..\src\audio\Player.h" />
<ClInclude Include="..\..\src\audio\Transcoder.h" />
<ClInclude Include="..\..\src\audio\Voice.h" />
<ClInclude Include="..\..\src\core\Action.h" /> <ClInclude Include="..\..\src\core\Action.h" />
<ClInclude Include="..\..\src\core\ActionGroup.h" /> <ClInclude Include="..\..\src\core\ActionGroup.h" />
<ClInclude Include="..\..\src\core\ActionHelper.h" /> <ClInclude Include="..\..\src\core\ActionHelper.h" />
@ -8,10 +14,11 @@
<ClInclude Include="..\..\src\core\ActionManager.h" /> <ClInclude Include="..\..\src\core\ActionManager.h" />
<ClInclude Include="..\..\src\core\Animation.h" /> <ClInclude Include="..\..\src\core\Animation.h" />
<ClInclude Include="..\..\src\core\Array.h" /> <ClInclude Include="..\..\src\core\Array.h" />
<ClInclude Include="..\..\src\core\audio.h" />
<ClInclude Include="..\..\src\core\Canvas.h" /> <ClInclude Include="..\..\src\core\Canvas.h" />
<ClInclude Include="..\..\src\core\closure.hpp" /> <ClInclude Include="..\..\src\core\closure.hpp" />
<ClInclude Include="..\..\src\core\Color.h" /> <ClInclude Include="..\..\src\core\Color.h" />
<ClInclude Include="..\..\src\core\Component.h" />
<ClInclude Include="..\..\src\core\ComPtr.hpp" />
<ClInclude Include="..\..\src\core\config.h" /> <ClInclude Include="..\..\src\core\config.h" />
<ClInclude Include="..\..\src\core\DebugNode.h" /> <ClInclude Include="..\..\src\core\DebugNode.h" />
<ClInclude Include="..\..\src\core\Event.hpp" /> <ClInclude Include="..\..\src\core\Event.hpp" />
@ -32,7 +39,6 @@
<ClInclude Include="..\..\src\core\logs.h" /> <ClInclude Include="..\..\src\core\logs.h" />
<ClInclude Include="..\..\src\core\macros.h" /> <ClInclude Include="..\..\src\core\macros.h" />
<ClInclude Include="..\..\src\core\modules.h" /> <ClInclude Include="..\..\src\core\modules.h" />
<ClInclude Include="..\..\src\core\Music.h" />
<ClInclude Include="..\..\src\core\Node.h" /> <ClInclude Include="..\..\src\core\Node.h" />
<ClInclude Include="..\..\src\core\noncopyable.hpp" /> <ClInclude Include="..\..\src\core\noncopyable.hpp" />
<ClInclude Include="..\..\src\core\Object.h" /> <ClInclude Include="..\..\src\core\Object.h" />
@ -69,18 +75,21 @@
<ClInclude Include="..\..\src\utils\Data.h" /> <ClInclude Include="..\..\src\utils\Data.h" />
<ClInclude Include="..\..\src\utils\File.h" /> <ClInclude Include="..\..\src\utils\File.h" />
<ClInclude Include="..\..\src\utils\Path.h" /> <ClInclude Include="..\..\src\utils\Path.h" />
<ClInclude Include="..\..\src\utils\Player.h" />
<ClInclude Include="..\..\src\utils\ResLoader.h" /> <ClInclude Include="..\..\src\utils\ResLoader.h" />
<ClInclude Include="..\..\src\utils\string.h" /> <ClInclude Include="..\..\src\utils\string.h" />
<ClInclude Include="..\..\src\utils\Transcoder.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\audio\audio.cpp" />
<ClCompile Include="..\..\src\audio\audio-modules.cpp" />
<ClCompile Include="..\..\src\audio\Music.cpp" />
<ClCompile Include="..\..\src\audio\Player.cpp" />
<ClCompile Include="..\..\src\audio\Transcoder.cpp" />
<ClCompile Include="..\..\src\audio\Voice.cpp" />
<ClCompile Include="..\..\src\core\Action.cpp" /> <ClCompile Include="..\..\src\core\Action.cpp" />
<ClCompile Include="..\..\src\core\ActionGroup.cpp" /> <ClCompile Include="..\..\src\core\ActionGroup.cpp" />
<ClCompile Include="..\..\src\core\ActionTween.cpp" /> <ClCompile Include="..\..\src\core\ActionTween.cpp" />
<ClCompile Include="..\..\src\core\ActionManager.cpp" /> <ClCompile Include="..\..\src\core\ActionManager.cpp" />
<ClCompile Include="..\..\src\core\Animation.cpp" /> <ClCompile Include="..\..\src\core\Animation.cpp" />
<ClCompile Include="..\..\src\core\audio.cpp" />
<ClCompile Include="..\..\src\core\Canvas.cpp" /> <ClCompile Include="..\..\src\core\Canvas.cpp" />
<ClCompile Include="..\..\src\core\Color.cpp" /> <ClCompile Include="..\..\src\core\Color.cpp" />
<ClCompile Include="..\..\src\core\DebugNode.cpp" /> <ClCompile Include="..\..\src\core\DebugNode.cpp" />
@ -94,7 +103,6 @@
<ClCompile Include="..\..\src\core\Input.cpp" /> <ClCompile Include="..\..\src\core\Input.cpp" />
<ClCompile Include="..\..\src\core\logs.cpp" /> <ClCompile Include="..\..\src\core\logs.cpp" />
<ClCompile Include="..\..\src\core\modules.cpp" /> <ClCompile Include="..\..\src\core\modules.cpp" />
<ClCompile Include="..\..\src\core\Music.cpp" />
<ClCompile Include="..\..\src\core\Node.cpp" /> <ClCompile Include="..\..\src\core\Node.cpp" />
<ClCompile Include="..\..\src\core\Object.cpp" /> <ClCompile Include="..\..\src\core\Object.cpp" />
<ClCompile Include="..\..\src\core\render.cpp" /> <ClCompile Include="..\..\src\core\render.cpp" />
@ -117,10 +125,8 @@
<ClCompile Include="..\..\src\utils\Data.cpp" /> <ClCompile Include="..\..\src\utils\Data.cpp" />
<ClCompile Include="..\..\src\utils\File.cpp" /> <ClCompile Include="..\..\src\utils\File.cpp" />
<ClCompile Include="..\..\src\utils\Path.cpp" /> <ClCompile Include="..\..\src\utils\Path.cpp" />
<ClCompile Include="..\..\src\utils\Player.cpp" />
<ClCompile Include="..\..\src\utils\ResLoader.cpp" /> <ClCompile Include="..\..\src\utils\ResLoader.cpp" />
<ClCompile Include="..\..\src\utils\string.cpp" /> <ClCompile Include="..\..\src\utils\string.cpp" />
<ClCompile Include="..\..\src\utils\Transcoder.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">

View File

@ -16,15 +16,15 @@
<Filter Include="dx"> <Filter Include="dx">
<UniqueIdentifier>{a9793a75-3212-4e31-a443-b23f18a1e136}</UniqueIdentifier> <UniqueIdentifier>{a9793a75-3212-4e31-a443-b23f18a1e136}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="audio">
<UniqueIdentifier>{836608a6-7443-48f9-8acd-18d3ba664348}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\src\easy2d.h" /> <ClInclude Include="..\..\src\easy2d.h" />
<ClInclude Include="..\..\src\core\Animation.h"> <ClInclude Include="..\..\src\core\Animation.h">
<Filter>core</Filter> <Filter>core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\core\audio.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\Canvas.h"> <ClInclude Include="..\..\src\core\Canvas.h">
<Filter>core</Filter> <Filter>core</Filter>
</ClInclude> </ClInclude>
@ -94,21 +94,12 @@
<ClInclude Include="..\..\src\utils\Path.h"> <ClInclude Include="..\..\src\utils\Path.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\utils\Player.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\src\utils\Transcoder.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ui\Button.h"> <ClInclude Include="..\..\src\ui\Button.h">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ui\Menu.h"> <ClInclude Include="..\..\src\ui\Menu.h">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\core\Music.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\Singleton.hpp"> <ClInclude Include="..\..\src\core\Singleton.hpp">
<Filter>core</Filter> <Filter>core</Filter>
</ClInclude> </ClInclude>
@ -232,14 +223,35 @@
<ClInclude Include="..\..\src\dx\D3D10DeviceResources.h"> <ClInclude Include="..\..\src\dx\D3D10DeviceResources.h">
<Filter>dx</Filter> <Filter>dx</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\audio\audio.h">
<Filter>audio</Filter>
</ClInclude>
<ClInclude Include="..\..\src\audio\Music.h">
<Filter>audio</Filter>
</ClInclude>
<ClInclude Include="..\..\src\audio\Player.h">
<Filter>audio</Filter>
</ClInclude>
<ClInclude Include="..\..\src\audio\Transcoder.h">
<Filter>audio</Filter>
</ClInclude>
<ClInclude Include="..\..\src\audio\Voice.h">
<Filter>audio</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\Component.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\audio\audio-modules.h">
<Filter>audio</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\ComPtr.hpp">
<Filter>core</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\core\Animation.cpp"> <ClCompile Include="..\..\src\core\Animation.cpp">
<Filter>core</Filter> <Filter>core</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\audio.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\Canvas.cpp"> <ClCompile Include="..\..\src\core\Canvas.cpp">
<Filter>core</Filter> <Filter>core</Filter>
</ClCompile> </ClCompile>
@ -297,21 +309,12 @@
<ClCompile Include="..\..\src\utils\Path.cpp"> <ClCompile Include="..\..\src\utils\Path.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\utils\Player.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\src\utils\Transcoder.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ui\Button.cpp"> <ClCompile Include="..\..\src\ui\Button.cpp">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\ui\Menu.cpp"> <ClCompile Include="..\..\src\ui\Menu.cpp">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\Music.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\TaskManager.cpp"> <ClCompile Include="..\..\src\core\TaskManager.cpp">
<Filter>core</Filter> <Filter>core</Filter>
</ClCompile> </ClCompile>
@ -372,5 +375,23 @@
<ClCompile Include="..\..\src\dx\D3D10DeviceResources.cpp"> <ClCompile Include="..\..\src\dx\D3D10DeviceResources.cpp">
<Filter>dx</Filter> <Filter>dx</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\audio\audio.cpp">
<Filter>audio</Filter>
</ClCompile>
<ClCompile Include="..\..\src\audio\Music.cpp">
<Filter>audio</Filter>
</ClCompile>
<ClCompile Include="..\..\src\audio\Player.cpp">
<Filter>audio</Filter>
</ClCompile>
<ClCompile Include="..\..\src\audio\Transcoder.cpp">
<Filter>audio</Filter>
</ClCompile>
<ClCompile Include="..\..\src\audio\Voice.cpp">
<Filter>audio</Filter>
</ClCompile>
<ClCompile Include="..\..\src\audio\audio-modules.cpp">
<Filter>audio</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -25,11 +25,10 @@ class DemoApp
public: public:
DemoApp() DemoApp()
{ {
Options options; // 使用 Audio 组件
options.title = L"Easy2DʾÀý³ÌÐò"; Use(&Audio::Instance());
options.width = WINDOW_WIDTH;
options.height = WINDOW_HEIGHT;
Options options(L"Easy2D示例程序", WINDOW_WIDTH, WINDOW_HEIGHT);
Init(options); Init(options);
} }

View File

@ -19,12 +19,10 @@
// THE SOFTWARE. // THE SOFTWARE.
#include "Music.h" #include "Music.h"
#include "../utils/Transcoder.h" #include "Transcoder.h"
#include "../utils/File.h"
#include "../utils/string.h"
#include "modules.h"
#include "audio.h" #include "audio.h"
#include "logs.h" #include "../core/logs.h"
#include "../core/modules.h"
namespace easy2d namespace easy2d
{ {
@ -60,7 +58,7 @@ namespace easy2d
if (res.IsFileType()) if (res.IsFileType())
{ {
if (!File(res.GetFileName()).Exists()) if (!modules::Shlwapi::Get().PathFileExistsW(res.GetFileName().c_str()))
{ {
E2D_WARNING_LOG(L"Media file '%s' not found", res.GetFileName().c_str()); E2D_WARNING_LOG(L"Media file '%s' not found", res.GetFileName().c_str());
return false; return false;

View File

@ -19,13 +19,15 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "include-forwards.h" #include "../core/include-forwards.h"
#include "audio.h" #include "../core/Resource.h"
#include "Resource.h" #include "Voice.h"
namespace easy2d namespace easy2d
{ {
// 稜있 E2D_DECLARE_SMART_PTR(Music);
// 音乐对象
class E2D_API Music class E2D_API Music
: public virtual Object : public virtual Object
{ {

View File

@ -19,7 +19,6 @@
// THE SOFTWARE. // THE SOFTWARE.
#include "Player.h" #include "Player.h"
#include "../core/Music.h"
namespace easy2d namespace easy2d
{ {

View File

@ -20,14 +20,15 @@
#pragma once #pragma once
#include "../core/include-forwards.h" #include "../core/include-forwards.h"
#include "../core/Resource.h" #include "Music.h"
#include <unordered_map>
namespace easy2d namespace easy2d
{ {
E2D_DECLARE_SMART_PTR(Player);
// 音乐播放器 // 音乐播放器
class E2D_API Player class E2D_API Player
: protected Noncopyable : protected Object
{ {
using MusicMap = Map<size_t, MusicPtr>; using MusicMap = Map<size_t, MusicPtr>;

View File

@ -23,10 +23,10 @@
#endif #endif
#include "Transcoder.h" #include "Transcoder.h"
#include "../core/modules.h" #include "audio-modules.h"
#include "../core/ComPtr.hpp"
#include "../core/logs.h" #include "../core/logs.h"
#include "../DX/helper.hpp" #include "../core/modules.h"
#include <shlwapi.h>
namespace easy2d namespace easy2d
{ {

View File

@ -19,7 +19,6 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "../core/macros.h"
#include "../core/Resource.h" #include "../core/Resource.h"
#include <mfapi.h> #include <mfapi.h>
#include <mfidl.h> #include <mfidl.h>

View File

@ -18,20 +18,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include "Voice.h"
#include "audio.h" #include "audio.h"
#include "include-forwards.h"
#include "modules.h"
#include "logs.h"
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <assert.h>
namespace easy2d namespace easy2d
{ {
//-------------------------------------------------------
// Voice
//-------------------------------------------------------
Voice::Voice() Voice::Voice()
: source_voice_(nullptr) : source_voice_(nullptr)
{ {
@ -154,93 +145,4 @@ namespace easy2d
source_voice_ = source_voice; source_voice_ = source_voice;
} }
//-------------------------------------------------------
// Audio
//-------------------------------------------------------
Audio::Audio()
: x_audio2_(nullptr)
, mastering_voice_(nullptr)
{
}
Audio::~Audio()
{
}
HRESULT Audio::Init()
{
E2D_LOG(L"Creating audio resources");
HRESULT hr = modules::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
if (SUCCEEDED(hr))
{
hr = modules::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
}
if (SUCCEEDED(hr))
{
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
}
return hr;
}
void Audio::Destroy()
{
E2D_LOG(L"Destroying audio resources");
ClearVoiceCache();
if (mastering_voice_)
{
mastering_voice_->DestroyVoice();
mastering_voice_ = nullptr;
}
DX::SafeRelease(x_audio2_);
modules::MediaFoundation::Get().MFShutdown();
}
HRESULT Audio::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx)
{
HRESULT hr;
IXAudio2SourceVoice* source_voice;
hr = x_audio2_->CreateSourceVoice(&source_voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (SUCCEEDED(hr))
{
voice.SetSourceVoice(source_voice);
voice_cache_.insert(&voice);
}
return hr;
}
void Audio::DeleteVoice(Voice* voice)
{
voice_cache_.erase(voice);
}
void Audio::ClearVoiceCache()
{
for (auto voice : voice_cache_)
{
voice->Destroy();
}
voice_cache_.clear();
}
void Audio::Open()
{
x_audio2_->StartEngine();
}
void Audio::Close()
{
x_audio2_->StopEngine();
}
} }

View File

@ -19,10 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "macros.h" #include "../core/macros.h"
#include "helper.hpp" #include "../core/noncopyable.hpp"
#include "Singleton.hpp"
#include "noncopyable.hpp"
#include <xaudio2.h> #include <xaudio2.h>
namespace easy2d namespace easy2d
@ -73,44 +71,4 @@ namespace easy2d
IXAudio2SourceVoice* source_voice_; IXAudio2SourceVoice* source_voice_;
}; };
class E2D_API Audio
: public Singleton<Audio>
{
E2D_DECLARE_SINGLETON(Audio);
using VoiceMap = UnorderedSet<Voice*>;
public:
HRESULT Init();
void Destroy();
// ¿ªÆôÉ豸
void Open();
// ¹Ø±ÕÉ豸
void Close();
HRESULT CreateVoice(
Voice& voice,
const WAVEFORMATEX* wfx
);
void DeleteVoice(
Voice* voice
);
void ClearVoiceCache();
protected:
Audio();
~Audio();
protected:
VoiceMap voice_cache_;
IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;
};
} }

View File

@ -0,0 +1,94 @@
// Copyright (c) 2016-2018 Easy2D - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "audio-modules.h"
#include "../core/logs.h"
namespace easy2d
{
namespace modules
{
XAudio2::XAudio2()
{
const auto xaudio2_dll_names =
{
L"xaudio2_9.dll",
L"xaudio2_8.dll",
L"xaudio2_7.dll"
};
for (const auto& name : xaudio2_dll_names)
{
xaudio2 = LoadLibraryW(name);
if (xaudio2)
{
XAudio2Create = (PFN_XAudio2Create)
GetProcAddress(xaudio2, "XAudio2Create");
break;
}
}
if (!xaudio2)
{
E2D_LOG(L"load xaudio2.dll failed");
}
}
MediaFoundation::MediaFoundation()
{
mfplat = LoadLibraryW(L"Mfplat.dll");
if (mfplat)
{
MFStartup = (PFN_MFStartup)
GetProcAddress(mfplat, "MFStartup");
MFShutdown = (PFN_MFShutdown)
GetProcAddress(mfplat, "MFShutdown");
MFCreateMediaType = (PFN_MFCreateMediaType)
GetProcAddress(mfplat, "MFCreateMediaType");
MFCreateWaveFormatExFromMFMediaType = (PFN_MFCreateWaveFormatExFromMFMediaType)
GetProcAddress(mfplat, "MFCreateWaveFormatExFromMFMediaType");
MFCreateMFByteStreamOnStream = (PFN_MFCreateMFByteStreamOnStream)
GetProcAddress(mfplat, "MFCreateMFByteStreamOnStream");
}
else
{
E2D_LOG(L"load Mfplat.dll failed");
}
mfreadwrite = LoadLibraryW(L"Mfreadwrite.dll");
if (mfreadwrite)
{
MFCreateSourceReaderFromURL = (PFN_MFCreateSourceReaderFromURL)
GetProcAddress(mfreadwrite, "MFCreateSourceReaderFromURL");
MFCreateSourceReaderFromByteStream = (PFN_MFCreateSourceReaderFromByteStream)
GetProcAddress(mfreadwrite, "MFCreateSourceReaderFromByteStream");
}
else
{
E2D_LOG(L"load Mfreadwrite.dll failed");
}
}
}
}

84
src/audio/audio-modules.h Normal file
View File

@ -0,0 +1,84 @@
// Copyright (c) 2016-2018 Easy2D - 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 "../core/macros.h"
#include <xaudio2.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
namespace easy2d
{
namespace modules
{
class E2D_API XAudio2
{
XAudio2();
HMODULE xaudio2;
// XAudio2 functions
typedef HRESULT(WINAPI *PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
public:
static XAudio2& Get()
{
static XAudio2 instance;
return instance;
}
PFN_XAudio2Create XAudio2Create;
};
class E2D_API MediaFoundation
{
MediaFoundation();
HMODULE mfplat;
HMODULE mfreadwrite;
// MediaFoundation functions
typedef HRESULT(WINAPI *PFN_MFStartup)(ULONG, DWORD);
typedef HRESULT(WINAPI *PFN_MFShutdown)();
typedef HRESULT(WINAPI *PFN_MFCreateMediaType)(IMFMediaType**);
typedef HRESULT(WINAPI *PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
typedef HRESULT(WINAPI *PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI *PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI *PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
public:
static MediaFoundation& Get()
{
static MediaFoundation instance;
return instance;
}
PFN_MFStartup MFStartup;
PFN_MFShutdown MFShutdown;
PFN_MFCreateMediaType MFCreateMediaType;
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
};
}
}

111
src/audio/audio.cpp Normal file
View File

@ -0,0 +1,111 @@
// Copyright (c) 2016-2018 Easy2D - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "audio.h"
#include "audio-modules.h"
#include "../core/logs.h"
namespace easy2d
{
Audio::Audio()
: x_audio2_(nullptr)
, mastering_voice_(nullptr)
{
}
Audio::~Audio()
{
}
void Audio::Setup()
{
E2D_LOG(L"Creating audio resources");
HRESULT hr = modules::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
if (SUCCEEDED(hr))
{
hr = modules::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
}
if (SUCCEEDED(hr))
{
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
}
ThrowIfFailed(hr);
}
void Audio::Destroy()
{
E2D_LOG(L"Destroying audio resources");
ClearVoiceCache();
if (mastering_voice_)
{
mastering_voice_->DestroyVoice();
mastering_voice_ = nullptr;
}
DX::SafeRelease(x_audio2_);
modules::MediaFoundation::Get().MFShutdown();
}
HRESULT Audio::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx)
{
HRESULT hr;
IXAudio2SourceVoice* source_voice;
hr = x_audio2_->CreateSourceVoice(&source_voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (SUCCEEDED(hr))
{
voice.SetSourceVoice(source_voice);
voice_cache_.insert(&voice);
}
return hr;
}
void Audio::DeleteVoice(Voice* voice)
{
voice_cache_.erase(voice);
}
void Audio::ClearVoiceCache()
{
for (auto voice : voice_cache_)
{
voice->Destroy();
}
voice_cache_.clear();
}
void Audio::Open()
{
x_audio2_->StartEngine();
}
void Audio::Close()
{
x_audio2_->StopEngine();
}
}

69
src/audio/audio.h Normal file
View File

@ -0,0 +1,69 @@
// Copyright (c) 2016-2018 Easy2D - 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 "../core/include-forwards.h"
#include "../core/Singleton.hpp"
#include "../core/Component.h"
#include "Voice.h"
namespace easy2d
{
class E2D_API Audio
: public Singleton<Audio>
, public Component
{
E2D_DECLARE_SINGLETON(Audio);
using VoiceMap = UnorderedSet<Voice*>;
public:
void Setup() override;
void Destroy() override;
// ¿ªÆôÉ豸
void Open();
// ¹Ø±ÕÉ豸
void Close();
HRESULT CreateVoice(
Voice& voice,
const WAVEFORMATEX* wfx
);
void DeleteVoice(
Voice* voice
);
void ClearVoiceCache();
protected:
Audio();
~Audio();
protected:
VoiceMap voice_cache_;
IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;
};
}

View File

@ -22,6 +22,8 @@
#include "logs.h" #include "logs.h"
#include "modules.h" #include "modules.h"
#include "render.h" #include "render.h"
#include "window.h"
#include "input.h"
#include "Event.hpp" #include "Event.hpp"
#include "Scene.h" #include "Scene.h"
#include "DebugNode.h" #include "DebugNode.h"
@ -49,6 +51,9 @@ namespace easy2d
, app_name_(app_name) , app_name_(app_name)
{ {
::CoInitialize(nullptr); ::CoInitialize(nullptr);
Use(&Renderer::Instance());
Use(&Input::Instance());
} }
Application::~Application() Application::~Application()
@ -61,7 +66,7 @@ namespace easy2d
void Application::Init(const Options& options) void Application::Init(const Options& options)
{ {
ThrowIfFailed( ThrowIfFailed(
Window::Instance().Init( Window::Instance().Create(
options.title, options.title,
options.width, options.width,
options.height, options.height,
@ -73,22 +78,15 @@ namespace easy2d
HWND hwnd = Window::Instance().GetHandle(); HWND hwnd = Window::Instance().GetHandle();
ThrowIfFailed( Renderer::Instance().SetTargetWindow(hwnd);
Renderer::Instance().Init(hwnd)
);
Renderer::Instance().SetClearColor(options.clear_color); Renderer::Instance().SetClearColor(options.clear_color);
Renderer::Instance().SetVSyncEnabled(options.vsync); Renderer::Instance().SetVSyncEnabled(options.vsync);
ThrowIfFailed( // Setup all components
Input::Instance().Init( for (Component* c : components_)
hwnd {
) c->Setup();
); }
ThrowIfFailed(
Audio::Instance().Init()
);
OnStart(); OnStart();
@ -139,12 +137,47 @@ namespace easy2d
curr_scene_.Reset(); curr_scene_.Reset();
debug_node_.Reset(); debug_node_.Reset();
Audio::Instance().Destroy(); for (auto iter = components_.rbegin(); iter != components_.rend(); ++iter)
Renderer::Instance().Destroy(); {
(*iter)->Destroy();
}
Window::Instance().Destroy(); Window::Instance().Destroy();
} }
} }
void Application::Use(Component* component)
{
if (component)
{
#if defined(E2D_DEBUG)
if (components_.contains(component))
{
E2D_ASSERT(false && "Component already exists!");
}
#endif
components_.push_back(component);
}
}
void Application::Remove(Component* component)
{
if (component)
{
for (auto iter = components_.begin(); iter != components_.end(); iter++)
{
if ((*iter) == component)
{
(*iter)->Destroy();
components_.erase(iter);
break;
}
}
}
}
void Application::EnterScene(ScenePtr const & scene) void Application::EnterScene(ScenePtr const & scene)
{ {
E2D_ASSERT(scene && "Application::EnterScene failed, NULL pointer exception"); E2D_ASSERT(scene && "Application::EnterScene failed, NULL pointer exception");
@ -190,12 +223,12 @@ namespace easy2d
if (show) if (show)
{ {
debug_node_ = new DebugNode; debug_node_ = new DebugNode;
Renderer::Instance().StartCollectStatus(); Renderer::Instance().StartCollectData();
} }
else else
{ {
debug_node_.Reset(); debug_node_.Reset();
Renderer::Instance().StopCollectStatus(); Renderer::Instance().StopCollectData();
} }
} }
@ -377,6 +410,14 @@ namespace easy2d
app->curr_scene_->Dispatch(evt); app->curr_scene_->Dispatch(evt);
} }
if (msg == WM_MOUSEMOVE)
{
Input::Instance().UpdateMousePos(
static_cast<float>(GET_X_LPARAM(lparam)),
static_cast<float>(GET_Y_LPARAM(lparam))
);
}
} }
break; break;

View File

@ -21,9 +21,7 @@
#pragma once #pragma once
#include "include-forwards.h" #include "include-forwards.h"
#include "time.h" #include "time.h"
#include "window.h" #include "Component.h"
#include "input.h"
#include "audio.h"
namespace easy2d namespace easy2d
{ {
@ -46,6 +44,24 @@ namespace easy2d
, vsync(true) , vsync(true)
, fullscreen(false) , fullscreen(false)
{} {}
Options(
String const& title,
int width,
int height,
LPCWSTR icon = nullptr,
Color clear_color = Color::Black,
bool vsync = true,
bool fullscreen = false
)
: title(title)
, width(width)
, height(height)
, icon(icon)
, clear_color(clear_color)
, vsync(vsync)
, fullscreen(fullscreen)
{}
}; };
@ -61,7 +77,7 @@ namespace easy2d
// 初始化 // 初始化
void Init( void Init(
Options const& options = Options{} Options const& options
); );
// 启动时 // 启动时
@ -88,6 +104,16 @@ namespace easy2d
// 销毁 // 销毁
void Destroy(); void Destroy();
// Ìí¼Ó×é¼þ
void Use(
Component* component
);
// Ð¶ÔØ×é¼þ
void Remove(
Component* component
);
// 切换场景 // 切换场景
void EnterScene( void EnterScene(
ScenePtr const& scene /* 场景 */ ScenePtr const& scene /* 场景 */
@ -136,5 +162,7 @@ namespace easy2d
ScenePtr next_scene_; ScenePtr next_scene_;
NodePtr debug_node_; NodePtr debug_node_;
TransitionPtr transition_; TransitionPtr transition_;
Array<Component*> components_;
}; };
} }

View File

@ -28,7 +28,7 @@ namespace easy2d
// Lightweight std::vector<>-like class // Lightweight std::vector<>-like class
// //
template<typename _Ty, typename _Alloc = std::allocator<_Ty>> template<typename _Ty, typename _Alloc = std::allocator<_Ty>>
class Array : _Alloc class Array
{ {
public: public:
using value_type = _Ty; using value_type = _Ty;
@ -78,25 +78,27 @@ namespace easy2d
inline void resize(int new_size) { if (new_size > capacity_) { reserve(_grow_capacity(new_size)); } _Ty tmp; std::uninitialized_fill_n(data_ + size_, new_size - size_, tmp); size_ = new_size; } inline void resize(int new_size) { if (new_size > capacity_) { reserve(_grow_capacity(new_size)); } _Ty tmp; std::uninitialized_fill_n(data_ + size_, new_size - size_, tmp); size_ = new_size; }
inline void resize(int new_size, const _Ty& v) { if (new_size > capacity_) reserve(_grow_capacity(new_size)); if (new_size > size_) std::uninitialized_fill_n(data_ + size_, new_size - size_, v); size_ = new_size; } inline void resize(int new_size, const _Ty& v) { if (new_size > capacity_) reserve(_grow_capacity(new_size)); if (new_size > size_) std::uninitialized_fill_n(data_ + size_, new_size - size_, v); size_ = new_size; }
inline void reserve(int new_capacity) { if (new_capacity <= capacity_) return; _Ty* new_data = _Alloc::allocate(new_capacity); if (data_) { ::memcpy(new_data, data_, (size_t)size_ * sizeof(_Ty)); _Alloc::deallocate(data_, capacity_); } data_ = new_data; capacity_ = new_capacity; } inline void reserve(int new_capacity) { if (new_capacity <= capacity_) return; _Ty* new_data = allocator_.allocate(new_capacity); if (data_) { ::memcpy(new_data, data_, (size_t)size_ * sizeof(_Ty)); allocator_.deallocate(data_, capacity_); } data_ = new_data; capacity_ = new_capacity; }
inline void push_back(const _Ty& v) { if (size_ == capacity_) reserve(_grow_capacity(size_ + 1)); _Alloc::construct(data_ + size_, v); size_++; } inline void push_back(const _Ty& v) { if (size_ == capacity_) reserve(_grow_capacity(size_ + 1)); allocator_.construct(data_ + size_, v); size_++; }
inline void pop_back() { if (empty()) throw std::out_of_range("vector empty before pop"); size_--; } inline void pop_back() { if (empty()) throw std::out_of_range("vector empty before pop"); size_--; }
inline void push_front(const _Ty& v) { if (size_ == 0) push_back(v); else insert(data_, v); } inline void push_front(const _Ty& v) { if (size_ == 0) push_back(v); else insert(data_, v); }
inline iterator erase(const_iterator it) { E2D_ASSERT(it >= data_ && it < data_ + size_); _Alloc::destroy(it); const ptrdiff_t off = it - data_; ::memmove(data_ + off, data_ + off + 1, ((size_t)size_ - (size_t)off - 1) * sizeof(_Ty)); size_--; return data_ + off; } inline iterator erase(const_iterator it) { E2D_ASSERT(it >= data_ && it < data_ + size_); allocator_.destroy(it); const ptrdiff_t off = it - data_; ::memmove(data_ + off, data_ + off + 1, ((size_t)size_ - (size_t)off - 1) * sizeof(_Ty)); size_--; return data_ + off; }
inline iterator erase(const_iterator it, const_iterator it_last) { E2D_ASSERT(it >= data_ && it < data_ + size_ && it_last > it && it_last <= data_ + size_); _destroy(it, it_last); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - data_; ::memmove(data_ + off, data_ + off + count, ((size_t)size_ - (size_t)off - count) * sizeof(_Ty)); size_ -= (int)count; return data_ + off; } inline iterator erase(const_iterator it, const_iterator it_last) { E2D_ASSERT(it >= data_ && it < data_ + size_ && it_last > it && it_last <= data_ + size_); _destroy(it, it_last); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - data_; ::memmove(data_ + off, data_ + off + count, ((size_t)size_ - (size_t)off - count) * sizeof(_Ty)); size_ -= (int)count; return data_ + off; }
inline iterator insert(const_iterator it, const _Ty& v) { E2D_ASSERT(it >= data_ && it <= data_ + size_); const ptrdiff_t off = it - data_; if (size_ == capacity_) reserve(_grow_capacity(size_ + 1)); if (off < (int)size_) ::memmove(data_ + off + 1, data_ + off, ((size_t)size_ - (size_t)off) * sizeof(_Ty)); _Alloc::construct(data_ + off, v); size_++; return data_ + off; } inline iterator insert(const_iterator it, const _Ty& v) { E2D_ASSERT(it >= data_ && it <= data_ + size_); const ptrdiff_t off = it - data_; if (size_ == capacity_) reserve(_grow_capacity(size_ + 1)); if (off < (int)size_) ::memmove(data_ + off + 1, data_ + off, ((size_t)size_ - (size_t)off) * sizeof(_Ty)); allocator_.construct(data_ + off, v); size_++; return data_ + off; }
inline bool contains(const _Ty& v) const { const _Ty* data = data_; const _Ty* data_end = data_ + size_; while (data < data_end) if (*data++ == v) return true; return false; } inline bool contains(const _Ty& v) const { const _Ty* data = data_; const _Ty* data_end = data_ + size_; while (data < data_end) if (*data++ == v) return true; return false; }
inline int index_of(const_iterator it) const { E2D_ASSERT(it >= data_ && it <= data_ + size_); const ptrdiff_t off = it - data_; return (int)off; } inline int index_of(const_iterator it) const { E2D_ASSERT(it >= data_ && it <= data_ + size_); const ptrdiff_t off = it - data_; return (int)off; }
private: private:
inline int _grow_capacity(int sz) const { int new_capacity = capacity_ ? (capacity_ + capacity_ / 2) : 8; return new_capacity > sz ? new_capacity : sz; } inline int _grow_capacity(int sz) const { int new_capacity = capacity_ ? (capacity_ + capacity_ / 2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void _destroy(iterator it, iterator it_last) { E2D_ASSERT(it >= data_ && it < data_ + size_ && it_last > it && it_last <= data_ + size_); for (; it != it_last; ++it) _Alloc::destroy(it); } inline void _destroy(iterator it, iterator it_last) { E2D_ASSERT(it >= data_ && it < data_ + size_ && it_last > it && it_last <= data_ + size_); for (; it != it_last; ++it) allocator_.destroy(it); }
inline void _destroy_all() { E2D_ASSERT((data_ && capacity_) || (!data_ && !capacity_)); if (size_) _destroy(begin(), end()); if (data_ && capacity_) _Alloc::deallocate(data_, capacity_); size_ = capacity_ = 0; data_ = nullptr; } inline void _destroy_all() { E2D_ASSERT((data_ && capacity_) || (!data_ && !capacity_)); if (size_) _destroy(begin(), end()); if (data_ && capacity_) allocator_.deallocate(data_, capacity_); size_ = capacity_ = 0; data_ = nullptr; }
private: private:
int size_; int size_;
int capacity_; int capacity_;
_Ty* data_; _Ty* data_;
typename _Alloc allocator_;
}; };
} }

41
src/core/ComPtr.hpp Normal file
View File

@ -0,0 +1,41 @@
// Copyright (c) 2016-2018 Easy2D - 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 "../core/IntrusivePtr.hpp"
#include <Unknwnbase.h>
namespace easy2d
{
// ComPtr<> is a smart pointer for COM
template <typename _Ty>
using ComPtr = IntrusivePtr<_Ty>;
inline void IntrusivePtrAddRef(IUnknown* ptr)
{
if (ptr) { ptr->AddRef(); }
}
inline void IntrusivePtrRelease(IUnknown* ptr)
{
if (ptr) { ptr->Release(); }
}
}

32
src/core/Component.h Normal file
View File

@ -0,0 +1,32 @@
// Copyright (c) 2016-2018 Easy2D - 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
namespace easy2d
{
class Component
{
public:
virtual void Setup() = 0;
virtual void Destroy() = 0;
};
}

View File

@ -21,7 +21,7 @@
#include "Image.h" #include "Image.h"
#include "logs.h" #include "logs.h"
#include "render.h" #include "render.h"
#include "../utils/File.h" #include "modules.h"
#include "../utils/string.h" #include "../utils/string.h"
namespace easy2d namespace easy2d
@ -62,7 +62,7 @@ namespace easy2d
if (res.IsFileType()) if (res.IsFileType())
{ {
if (!File(res.GetFileName()).Exists()) if (!modules::Shlwapi::Get().PathFileExistsW(res.GetFileName().c_str()))
{ {
E2D_WARNING_LOG(L"Image file '%s' not found!", res.GetFileName().c_str()); E2D_WARNING_LOG(L"Image file '%s' not found!", res.GetFileName().c_str());
return false; return false;

View File

@ -25,8 +25,9 @@
namespace easy2d namespace easy2d
{ {
Input::Input() Input::Input()
: hwnd_(nullptr) : want_update_(false)
, want_update_(false) , mouse_pos_x_(0.f)
, mouse_pos_y_(0.f)
{ {
ZeroMemory(keys_, sizeof(keys_)); ZeroMemory(keys_, sizeof(keys_));
ZeroMemory(keys_pressed_, sizeof(keys_pressed_)); ZeroMemory(keys_pressed_, sizeof(keys_pressed_));
@ -37,13 +38,6 @@ namespace easy2d
{ {
} }
HRESULT Input::Init(HWND hwnd)
{
hwnd_ = hwnd;
return S_OK;
}
void Input::Update() void Input::Update()
{ {
if (want_update_) if (want_update_)
@ -67,46 +61,42 @@ namespace easy2d
want_update_ = true; want_update_ = true;
} }
bool Input::IsDown(int code_or_btn) void Input::UpdateMousePos(float x, float y)
{ {
E2D_ASSERT(code_or_btn >= 0 && code_or_btn < 256); mouse_pos_x_ = x;
return keys_[code_or_btn]; mouse_pos_y_ = y;
} }
bool Input::WasPressed(int code_or_btn) bool Input::IsDown(int key_or_btn)
{ {
E2D_ASSERT(code_or_btn >= 0 && code_or_btn < 256); E2D_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
return keys_pressed_[code_or_btn]; return keys_[key_or_btn];
} }
bool Input::WasReleased(int code_or_btn) bool Input::WasPressed(int key_or_btn)
{ {
E2D_ASSERT(code_or_btn >= 0 && code_or_btn < 256); E2D_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
return keys_released_[code_or_btn]; return keys_pressed_[key_or_btn];
}
bool Input::WasReleased(int key_or_btn)
{
E2D_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
return keys_released_[key_or_btn];
} }
float Input::GetMouseX() float Input::GetMouseX()
{ {
return GetMousePos().x; return mouse_pos_x_;
} }
float Input::GetMouseY() float Input::GetMouseY()
{ {
return GetMousePos().y; return mouse_pos_y_;
} }
Point Input::GetMousePos() Point Input::GetMousePos()
{ {
Point mouse_pos = Point{}; return Point{ mouse_pos_x_, mouse_pos_y_ };
if (HWND active_window = ::GetForegroundWindow())
{
if (active_window == hwnd_ || ::IsChild(active_window, hwnd_))
{
POINT pos;
if (::GetCursorPos(&pos) && ::ScreenToClient(hwnd_, &pos))
mouse_pos = Point((float)pos.x, (float)pos.y);
}
}
return mouse_pos;
} }
} }

View File

@ -22,28 +22,30 @@
#include "include-forwards.h" #include "include-forwards.h"
#include "keys.hpp" #include "keys.hpp"
#include "Singleton.hpp" #include "Singleton.hpp"
#include "Component.h"
namespace easy2d namespace easy2d
{ {
class E2D_API Input class E2D_API Input
: public Singleton<Input> : public Singleton<Input>
, public Component
{ {
E2D_DECLARE_SINGLETON(Input); E2D_DECLARE_SINGLETON(Input);
public: public:
// 检测键盘或鼠标按键是否正被按下 // 检测键盘或鼠标按键是否正被按下
bool IsDown( bool IsDown(
int code_or_btn int key_or_btn
); );
// 检测键盘或鼠标按键是否刚被点击 // 检测键盘或鼠标按键是否刚被点击
bool WasPressed( bool WasPressed(
int code_or_btn int key_or_btn
); );
// 检测键盘或鼠标按键是否刚抬起 // 检测键盘或鼠标按键是否刚抬起
bool WasReleased( bool WasReleased(
int code_or_btn int key_or_btn
); );
// 获得鼠标 x 坐标 // 获得鼠标 x 坐标
@ -55,22 +57,30 @@ namespace easy2d
// 获得鼠标坐标 // 获得鼠标坐标
Point GetMousePos(); Point GetMousePos();
HRESULT Init(HWND hwnd); public:
void Setup() override {}
void Destroy() override {}
void Update(); void Update();
void UpdateKey(int, bool); void UpdateKey(int, bool);
void UpdateMousePos(float, float);
protected: protected:
Input(); Input();
~Input(); ~Input();
protected: protected:
HWND hwnd_; static const int KEY_NUM = 256;
bool want_update_; bool want_update_;
bool keys_[256]; bool keys_[KEY_NUM];
bool keys_pressed_[256]; bool keys_pressed_[KEY_NUM];
bool keys_released_[256]; bool keys_released_[KEY_NUM];
float mouse_pos_x_;
float mouse_pos_y_;
}; };
} }

View File

@ -15,7 +15,6 @@
//#define E2D_LOG(FORMAT, ...) wprintf(FORMAT L"\n", __VA_ARGS__) //#define E2D_LOG(FORMAT, ...) wprintf(FORMAT L"\n", __VA_ARGS__)
//#define E2D_WARNING_LOG(FORMAT, ...) wprintf(FORMAT L"\n", __VA_ARGS__) //#define E2D_WARNING_LOG(FORMAT, ...) wprintf(FORMAT L"\n", __VA_ARGS__)
//#define E2D_ERROR_LOG(FORMAT, ...) wprintf(FORMAT L"\n", __VA_ARGS__) //#define E2D_ERROR_LOG(FORMAT, ...) wprintf(FORMAT L"\n", __VA_ARGS__)
//#define E2D_ERROR_HR_LOG(HR, FORMAT, ...) E2D_ERROR_LOG(L"Failure with HRESULT of %08X " FORMAT L"\n", HR, __VA_ARGS__)
//---- Define attributes of all API symbols declarations for DLL //---- Define attributes of all API symbols declarations for DLL
//#define E2D_API __declspec( dllexport ) //#define E2D_API __declspec( dllexport )

View File

@ -21,6 +21,7 @@
#pragma once #pragma once
#include "RefCounter.hpp" #include "RefCounter.hpp"
#include "IntrusivePtr.hpp" #include "IntrusivePtr.hpp"
#include "ComPtr.hpp"
#include "Array.h" #include "Array.h"
#include "closure.hpp" #include "closure.hpp"
#include "../math/vector.hpp" #include "../math/vector.hpp"
@ -74,10 +75,8 @@ namespace easy2d
{ {
E2D_DECLARE_SMART_PTR(Object); E2D_DECLARE_SMART_PTR(Object);
E2D_DECLARE_SMART_PTR(Image); E2D_DECLARE_SMART_PTR(Image);
E2D_DECLARE_SMART_PTR(Music);
E2D_DECLARE_SMART_PTR(Task); E2D_DECLARE_SMART_PTR(Task);
E2D_DECLARE_SMART_PTR(Frames); E2D_DECLARE_SMART_PTR(Frames);
E2D_DECLARE_SMART_PTR(EventListener); E2D_DECLARE_SMART_PTR(EventListener);
E2D_DECLARE_SMART_PTR(Geometry); E2D_DECLARE_SMART_PTR(Geometry);

View File

@ -41,71 +41,5 @@ namespace easy2d
E2D_LOG(L"load shlapi.dll failed"); E2D_LOG(L"load shlapi.dll failed");
} }
} }
XAudio2::XAudio2()
{
const auto xaudio2_dll_names =
{
L"xaudio2_9.dll",
L"xaudio2_8.dll",
L"xaudio2_7.dll"
};
for (const auto& name : xaudio2_dll_names)
{
xaudio2 = LoadLibraryW(name);
if (xaudio2)
{
XAudio2Create = (PFN_XAudio2Create)
GetProcAddress(xaudio2, "XAudio2Create");
break;
}
}
if (!xaudio2)
{
E2D_LOG(L"load xaudio2.dll failed");
}
}
MediaFoundation::MediaFoundation()
{
mfplat = LoadLibraryW(L"Mfplat.dll");
if (mfplat)
{
MFStartup = (PFN_MFStartup)
GetProcAddress(mfplat, "MFStartup");
MFShutdown = (PFN_MFShutdown)
GetProcAddress(mfplat, "MFShutdown");
MFCreateMediaType = (PFN_MFCreateMediaType)
GetProcAddress(mfplat, "MFCreateMediaType");
MFCreateWaveFormatExFromMFMediaType = (PFN_MFCreateWaveFormatExFromMFMediaType)
GetProcAddress(mfplat, "MFCreateWaveFormatExFromMFMediaType");
MFCreateMFByteStreamOnStream = (PFN_MFCreateMFByteStreamOnStream)
GetProcAddress(mfplat, "MFCreateMFByteStreamOnStream");
}
else
{
E2D_LOG(L"load Mfplat.dll failed");
}
mfreadwrite = LoadLibraryW(L"Mfreadwrite.dll");
if (mfreadwrite)
{
MFCreateSourceReaderFromURL = (PFN_MFCreateSourceReaderFromURL)
GetProcAddress(mfreadwrite, "MFCreateSourceReaderFromURL");
MFCreateSourceReaderFromByteStream = (PFN_MFCreateSourceReaderFromByteStream)
GetProcAddress(mfreadwrite, "MFCreateSourceReaderFromByteStream");
}
else
{
E2D_LOG(L"load Mfreadwrite.dll failed");
}
}
} }
} }

View File

@ -49,58 +49,5 @@ namespace easy2d
PFN_PathFileExistsW PathFileExistsW; PFN_PathFileExistsW PathFileExistsW;
PFN_SHCreateMemStream SHCreateMemStream; PFN_SHCreateMemStream SHCreateMemStream;
}; };
class E2D_API XAudio2
{
XAudio2();
HMODULE xaudio2;
// XAudio2 functions
typedef HRESULT(WINAPI *PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
public:
static XAudio2& Get()
{
static XAudio2 instance;
return instance;
}
PFN_XAudio2Create XAudio2Create;
};
class E2D_API MediaFoundation
{
MediaFoundation();
HMODULE mfplat;
HMODULE mfreadwrite;
// MediaFoundation functions
typedef HRESULT(WINAPI *PFN_MFStartup)(ULONG, DWORD);
typedef HRESULT(WINAPI *PFN_MFShutdown)();
typedef HRESULT(WINAPI *PFN_MFCreateMediaType)(IMFMediaType**);
typedef HRESULT(WINAPI *PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
typedef HRESULT(WINAPI *PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI *PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI *PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
public:
static MediaFoundation& Get()
{
static MediaFoundation instance;
return instance;
}
PFN_MFStartup MFStartup;
PFN_MFShutdown MFShutdown;
PFN_MFCreateMediaType MFCreateMediaType;
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
};
} }
} }

View File

@ -20,19 +20,18 @@
#include "render.h" #include "render.h"
#include "logs.h" #include "logs.h"
#include "render.h"
#include "Image.h" #include "Image.h"
#include "Transform.hpp"
namespace easy2d namespace easy2d
{ {
Renderer::Renderer() Renderer::Renderer()
: antialias_(true) : hwnd_(nullptr)
, antialias_(true)
, vsync_(true) , vsync_(true)
, text_antialias_(TextAntialias::ClearType) , text_antialias_(TextAntialias::ClearType)
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) , clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
, opacity_(1.f) , opacity_(1.f)
, collecting_status_(false) , collecting_data_(false)
{ {
status_.primitives = 0; status_.primitives = 0;
} }
@ -41,17 +40,18 @@ namespace easy2d
{ {
} }
HRESULT Renderer::Init(HWND hwnd) void Renderer::Setup()
{ {
HRESULT hr = S_OK;
E2D_LOG(L"Creating device resources"); E2D_LOG(L"Creating device resources");
HRESULT hr = hwnd_ ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{ {
device_resources_ = nullptr; device_resources_ = nullptr;
hr = DeviceResources::Create( hr = DeviceResources::Create(
&device_resources_, &device_resources_,
hwnd hwnd_
); );
} }
@ -73,19 +73,25 @@ namespace easy2d
{ {
hr = CreateDeviceResources(); hr = CreateDeviceResources();
} }
return hr;
ThrowIfFailed(hr);
} }
void Renderer::Destroy() void Renderer::Destroy()
{ {
E2D_LOG(L"Destroying device resources"); E2D_LOG(L"Destroying device resources");
device_resources_.Reset();
factory_.Reset();
device_context_.Reset();
drawing_state_block_.Reset(); drawing_state_block_.Reset();
text_renderer_.Reset(); text_renderer_.Reset();
solid_color_brush_.Reset(); solid_color_brush_.Reset();
device_context_.Reset();
factory_.Reset();
device_resources_.Reset();
}
void Renderer::SetTargetWindow(HWND hwnd)
{
hwnd_ = hwnd;
} }
HRESULT Renderer::CreateDeviceResources() HRESULT Renderer::CreateDeviceResources()
@ -129,7 +135,7 @@ namespace easy2d
if (!device_context_) if (!device_context_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (collecting_status_) if (collecting_data_)
{ {
status_.start = time::Now(); status_.start = time::Now();
status_.primitives = 0; status_.primitives = 0;
@ -174,7 +180,7 @@ namespace easy2d
hr = HandleDeviceLost(); hr = HandleDeviceLost();
} }
if (collecting_status_) if (collecting_data_)
{ {
status_.duration = time::Now() - status_.start; status_.duration = time::Now() - status_.start;
} }
@ -209,7 +215,7 @@ namespace easy2d
device_resources_->GetStrokeStyle(stroke) device_resources_->GetStrokeStyle(stroke)
); );
if (collecting_status_) if (collecting_data_)
++status_.primitives; ++status_.primitives;
return S_OK; return S_OK;
} }
@ -244,7 +250,7 @@ namespace easy2d
DX::ConvertToRectF(image->GetCropRect()) DX::ConvertToRectF(image->GetCropRect())
); );
if (collecting_status_) if (collecting_data_)
++status_.primitives; ++status_.primitives;
return S_OK; return S_OK;
} }
@ -267,7 +273,7 @@ namespace easy2d
rect rect
); );
if (collecting_status_) if (collecting_data_)
++status_.primitives; ++status_.primitives;
return S_OK; return S_OK;
} }
@ -277,7 +283,7 @@ namespace easy2d
if (!text_renderer_) if (!text_renderer_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (collecting_status_) if (collecting_data_)
++status_.primitives; ++status_.primitives;
return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0); return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0);
} }
@ -338,14 +344,14 @@ namespace easy2d
return S_OK; return S_OK;
} }
void Renderer::StartCollectStatus() void Renderer::StartCollectData()
{ {
collecting_status_ = true; collecting_data_ = true;
} }
void Renderer::StopCollectStatus() void Renderer::StopCollectData()
{ {
collecting_status_ = false; collecting_data_ = false;
} }
void Renderer::SetClearColor(const Color & color) void Renderer::SetClearColor(const Color & color)

View File

@ -23,6 +23,7 @@
#include "Font.hpp" #include "Font.hpp"
#include "Resource.h" #include "Resource.h"
#include "TextStyle.hpp" #include "TextStyle.hpp"
#include "Component.h"
#include "Singleton.hpp" #include "Singleton.hpp"
#include "../DX/helper.hpp" #include "../DX/helper.hpp"
#include "../DX/DeviceResources.h" #include "../DX/DeviceResources.h"
@ -40,22 +41,11 @@ namespace easy2d
class E2D_API Renderer class E2D_API Renderer
: public Singleton<Renderer> : public Singleton<Renderer>
, public Component
{ {
E2D_DECLARE_SINGLETON(Renderer); E2D_DECLARE_SINGLETON(Renderer);
public: public:
HRESULT Init(HWND hwnd);
void Destroy();
inline RenderStatus const& GetStatus() const { return status_; }
inline DeviceResources* GetDeviceResources() const { return device_resources_.Get(); }
inline ITextRenderer* GetTextRenderer() const { return text_renderer_.Get(); }
inline ID2D1SolidColorBrush* GetSolidColorBrush() const { return solid_color_brush_.Get(); }
HRESULT BeginDraw(); HRESULT BeginDraw();
HRESULT EndDraw(); HRESULT EndDraw();
@ -140,9 +130,26 @@ namespace easy2d
HRESULT PopLayer(); HRESULT PopLayer();
void StartCollectStatus(); public:
void Setup() override;
void StopCollectStatus(); void Destroy() override;
void SetTargetWindow(HWND);
void StartCollectData();
void StopCollectData();
inline HWND GetTargetWindow() const { return hwnd_; }
inline RenderStatus const& GetStatus() const { return status_; }
inline DeviceResources* GetDeviceResources() const { return device_resources_.Get(); }
inline ITextRenderer* GetTextRenderer() const { return text_renderer_.Get(); }
inline ID2D1SolidColorBrush* GetSolidColorBrush() const { return solid_color_brush_.Get(); }
private: private:
Renderer(); Renderer();
@ -156,10 +163,11 @@ namespace easy2d
private: private:
unsigned long ref_count_; unsigned long ref_count_;
HWND hwnd_;
float opacity_; float opacity_;
bool antialias_; bool antialias_;
bool vsync_; bool vsync_;
bool collecting_status_; bool collecting_data_;
TextAntialias text_antialias_; TextAntialias text_antialias_;
D2D1_COLOR_F clear_color_; D2D1_COLOR_F clear_color_;

View File

@ -19,9 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#include "window.h" #include "window.h"
#include "render.h"
#include "logs.h" #include "logs.h"
#include "../math/scalar.hpp"
#define WINDOW_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX #define WINDOW_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP #define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP
@ -53,7 +51,7 @@ namespace easy2d
{ {
} }
HRESULT Window::Init(String title, int width, int height, LPCWSTR icon, bool fullscreen, WNDPROC proc) HRESULT Window::Create(String title, int width, int height, LPCWSTR icon, bool fullscreen, WNDPROC proc)
{ {
HINSTANCE hinst = GetModuleHandleW(nullptr); HINSTANCE hinst = GetModuleHandleW(nullptr);
WNDCLASSEX wcex = { 0 }; WNDCLASSEX wcex = { 0 };

View File

@ -54,7 +54,8 @@ namespace easy2d
// 设置全屏模式 // 设置全屏模式
void SetFullscreen(bool fullscreen, int width, int height); void SetFullscreen(bool fullscreen, int width, int height);
HRESULT Init( public:
HRESULT Create(
String title, String title,
int width, int width,
int height, int height,

View File

@ -19,7 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "../core/IntrusivePtr.hpp" #include "../core/ComPtr.hpp"
#include "../core/Color.h" #include "../core/Color.h"
#include "../math/vector.hpp" #include "../math/vector.hpp"
#include "../math/Rect.hpp" #include "../math/Rect.hpp"
@ -28,21 +28,6 @@
namespace easy2d namespace easy2d
{ {
// ComPtr<> is a smart pointer for COM
template <typename _Ty>
using ComPtr = IntrusivePtr<_Ty>;
inline void IntrusivePtrAddRef(IUnknown* ptr)
{
if (ptr) { ptr->AddRef(); }
}
inline void IntrusivePtrRelease(IUnknown* ptr)
{
if (ptr) { ptr->Release(); }
}
namespace DX namespace DX
{ {
template <typename T> template <typename T>

View File

@ -35,7 +35,6 @@
#include "core/render.h" #include "core/render.h"
#include "core/window.h" #include "core/window.h"
#include "core/input.h" #include "core/input.h"
#include "core/audio.h"
#include "core/time.h" #include "core/time.h"
#include "core/logs.h" #include "core/logs.h"
@ -45,15 +44,9 @@
#include "core/Transform.hpp" #include "core/Transform.hpp"
#include "core/TextStyle.hpp" #include "core/TextStyle.hpp"
#include "core/noncopyable.hpp"
#include "core/RefCounter.hpp"
#include "core/IntrusivePtr.hpp"
#include "core/IntrusiveList.hpp"
#include "core/Object.h" #include "core/Object.h"
#include "core/Image.h" #include "core/Image.h"
#include "core/Frames.h" #include "core/Frames.h"
#include "core/Music.h"
#include "core/Geometry.h" #include "core/Geometry.h"
#include "core/Task.h" #include "core/Task.h"
#include "core/TaskManager.h" #include "core/TaskManager.h"
@ -92,6 +85,15 @@
#include "math/Matrix.hpp" #include "math/Matrix.hpp"
//
// audio
//
#include "audio/audio.h"
#include "audio/Music.h"
#include "audio/Player.h"
// //
// utils // utils
// //
@ -99,8 +101,6 @@
#include "utils/Path.h" #include "utils/Path.h"
#include "utils/Data.h" #include "utils/Data.h"
#include "utils/File.h" #include "utils/File.h"
#include "utils/Player.h"
#include "utils/Transcoder.h"
#include "utils/ResLoader.h" #include "utils/ResLoader.h"

View File

@ -22,7 +22,7 @@
#include "../core/modules.h" #include "../core/modules.h"
#include "../core/Image.h" #include "../core/Image.h"
#include "../core/Frames.h" #include "../core/Frames.h"
#include "../core/Music.h" #include "../audio/Music.h"
namespace easy2d namespace easy2d
{ {

View File

@ -21,6 +21,7 @@
#pragma once #pragma once
#include "../core/include-forwards.h" #include "../core/include-forwards.h"
#include "../core/Resource.h" #include "../core/Resource.h"
#include "../audio/Music.h"
namespace easy2d namespace easy2d
{ {