mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-24 07:06:36 +00:00
Merge branch 'master' into mac
This commit is contained in:
@@ -103,6 +103,8 @@
|
|||||||
<ClInclude Include="..\GpCommon\GpDisplayDriverTickStatus.h" />
|
<ClInclude Include="..\GpCommon\GpDisplayDriverTickStatus.h" />
|
||||||
<ClInclude Include="..\GpCommon\GpFileCreationDisposition.h" />
|
<ClInclude Include="..\GpCommon\GpFileCreationDisposition.h" />
|
||||||
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h" />
|
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h" />
|
||||||
|
<ClInclude Include="..\GpCommon\GpString.h" />
|
||||||
|
<ClInclude Include="..\GpCommon\GpVector.h" />
|
||||||
<ClInclude Include="..\GpCommon\IGpCursor.h" />
|
<ClInclude Include="..\GpCommon\IGpCursor.h" />
|
||||||
<ClInclude Include="..\GpCommon\IGpAudioChannelCallbacks.h" />
|
<ClInclude Include="..\GpCommon\IGpAudioChannelCallbacks.h" />
|
||||||
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h" />
|
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h" />
|
||||||
|
@@ -93,6 +93,12 @@
|
|||||||
<ClInclude Include="GpBWCursor_Win32.h">
|
<ClInclude Include="GpBWCursor_Win32.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\GpCommon\GpVector.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\GpCommon\GpString.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Image Include="ConvertedResources\Large128.ico">
|
<Image Include="ConvertedResources\Large128.ico">
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
#include "IGpAllocator.h"
|
#include "IGpAllocator.h"
|
||||||
#include "IGpDirectoryCursor.h"
|
#include "IGpDirectoryCursor.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
#include <ShlObj.h>
|
#include <ShlObj.h>
|
||||||
#include <commdlg.h>
|
#include <commdlg.h>
|
||||||
@@ -105,48 +105,69 @@ GpDirectoryCursor_Win32::~GpDirectoryCursor_Win32()
|
|||||||
FindClose(m_handle);
|
FindClose(m_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
GpFileSystem_Win32::GpFileSystem_Win32()
|
GpFileSystem_Win32::GpFileSystem_Win32(IGpAllocator *alloc)
|
||||||
: m_alloc(GpAllocator_C::GetInstance())
|
: m_alloc(alloc)
|
||||||
|
, m_prefsDir(alloc)
|
||||||
|
, m_scoresDir(alloc)
|
||||||
|
, m_packagedDir(alloc)
|
||||||
|
, m_housesDir(alloc)
|
||||||
|
, m_logsDir(alloc)
|
||||||
|
, m_userHousesDir(alloc)
|
||||||
|
, m_userSavesDir(alloc)
|
||||||
|
, m_resourcesDir(alloc)
|
||||||
{
|
{
|
||||||
// GP TODO: This shouldn't be static init since it allocates memory
|
|
||||||
m_executablePath[0] = 0;
|
m_executablePath[0] = 0;
|
||||||
|
|
||||||
PWSTR docsPath;
|
|
||||||
if (!FAILED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &docsPath)))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_prefsDir = docsPath;
|
|
||||||
}
|
}
|
||||||
catch(...)
|
|
||||||
|
void GpFileSystem_Win32::Destroy()
|
||||||
|
{
|
||||||
|
IGpAllocator *alloc = m_alloc;
|
||||||
|
this->~GpFileSystem_Win32();
|
||||||
|
alloc->Release(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GpFileSystem_Win32::Init()
|
||||||
|
{
|
||||||
|
PWSTR docsPath;
|
||||||
|
if (FAILED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &docsPath)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_prefsDir.Set(docsPath))
|
||||||
{
|
{
|
||||||
CoTaskMemFree(docsPath);
|
CoTaskMemFree(docsPath);
|
||||||
throw;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_prefsDir.append(L"\\" GP_APPLICATION_NAME_W);
|
CoTaskMemFree(docsPath);
|
||||||
|
|
||||||
m_userHousesDir = m_prefsDir + L"\\Houses";
|
if (!m_prefsDir.Append(L"\\" GP_APPLICATION_NAME_W))
|
||||||
m_userSavesDir = m_prefsDir + L"\\SavedGames";
|
return false;
|
||||||
m_scoresDir = m_prefsDir + L"\\Scores";
|
|
||||||
m_logsDir = m_prefsDir + L"\\Logs";
|
|
||||||
m_fontCacheDir = m_prefsDir + L"\\FontCache";
|
|
||||||
|
|
||||||
CreateDirectoryW(m_prefsDir.c_str(), nullptr);
|
if (!m_userHousesDir.Set(m_prefsDir) || !m_userHousesDir.Append(L"\\Houses"))
|
||||||
CreateDirectoryW(m_scoresDir.c_str(), nullptr);
|
return false;
|
||||||
CreateDirectoryW(m_userHousesDir.c_str(), nullptr);
|
|
||||||
CreateDirectoryW(m_userSavesDir.c_str(), nullptr);
|
|
||||||
CreateDirectoryW(m_logsDir.c_str(), nullptr);
|
|
||||||
CreateDirectoryW(m_fontCacheDir.c_str(), nullptr);
|
|
||||||
|
|
||||||
m_prefsDir.append(L"\\");
|
if (!m_userSavesDir.Set(m_prefsDir) || !m_userSavesDir.Append(L"\\SavedGames"))
|
||||||
m_scoresDir.append(L"\\");
|
return false;
|
||||||
m_userHousesDir.append(L"\\");
|
|
||||||
m_userSavesDir.append(L"\\");
|
if (!m_scoresDir.Set(m_prefsDir) || !m_scoresDir.Append(L"\\Scores"))
|
||||||
m_logsDir.append(L"\\");
|
return false;
|
||||||
m_fontCacheDir.append(L"\\");
|
|
||||||
m_resourcesDir.append(L"\\");
|
if (!m_logsDir.Set(m_prefsDir) || !m_logsDir.Append(L"\\Logs"))
|
||||||
}
|
return false;
|
||||||
|
|
||||||
|
CreateDirectoryW(m_prefsDir.Buffer(), nullptr);
|
||||||
|
CreateDirectoryW(m_scoresDir.Buffer(), nullptr);
|
||||||
|
CreateDirectoryW(m_userHousesDir.Buffer(), nullptr);
|
||||||
|
CreateDirectoryW(m_userSavesDir.Buffer(), nullptr);
|
||||||
|
CreateDirectoryW(m_logsDir.Buffer(), nullptr);
|
||||||
|
|
||||||
|
if (!m_prefsDir.Append(L"\\") ||
|
||||||
|
!m_scoresDir.Append(L"\\") ||
|
||||||
|
!m_userHousesDir.Append(L"\\") ||
|
||||||
|
!m_userSavesDir.Append(L"\\") ||
|
||||||
|
!m_logsDir.Append(L"\\") ||
|
||||||
|
!m_resourcesDir.Append(L"\\"))
|
||||||
|
return false;
|
||||||
|
|
||||||
DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH);
|
DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH);
|
||||||
if (modulePathSize == MAX_PATH || modulePathSize == 0)
|
if (modulePathSize == MAX_PATH || modulePathSize == 0)
|
||||||
@@ -182,12 +203,19 @@ GpFileSystem_Win32::GpFileSystem_Win32()
|
|||||||
currentPathLength--;
|
currentPathLength--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentPathLength > 0)
|
if (currentPathLength == 0)
|
||||||
{
|
return false;
|
||||||
m_packagedDir = std::wstring(m_executablePath) + L"Packaged\\";
|
|
||||||
m_housesDir = std::wstring(m_executablePath) + L"Packaged\\Houses\\";
|
if (!m_packagedDir.Set(m_executablePath) || !m_packagedDir.Append(L"Packaged\\"))
|
||||||
m_resourcesDir = std::wstring(m_executablePath) + L"Resources\\";
|
return false;
|
||||||
}
|
|
||||||
|
if (!m_housesDir.Set(m_executablePath) || !m_housesDir.Append(L"Packaged\\Houses\\"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_resourcesDir.Set(m_executablePath) || !m_resourcesDir.Append(L"Resources\\"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GpFileSystem_Win32::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
|
bool GpFileSystem_Win32::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
|
||||||
@@ -428,9 +456,27 @@ const wchar_t *GpFileSystem_Win32::GetBasePath() const
|
|||||||
return m_executablePath;
|
return m_executablePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GpFileSystem_Win32 *GpFileSystem_Win32::CreateInstance(IGpAllocator *alloc)
|
||||||
|
{
|
||||||
|
void *storage = alloc->Alloc(sizeof(GpFileSystem_Win32));
|
||||||
|
if (!storage)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
GpFileSystem_Win32 *fs = new (storage) GpFileSystem_Win32(alloc);
|
||||||
|
if (!fs->Init())
|
||||||
|
{
|
||||||
|
fs->Destroy();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ms_instance = fs;
|
||||||
|
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
GpFileSystem_Win32 *GpFileSystem_Win32::GetInstance()
|
GpFileSystem_Win32 *GpFileSystem_Win32::GetInstance()
|
||||||
{
|
{
|
||||||
return &ms_instance;
|
return ms_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath)
|
bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath)
|
||||||
@@ -440,28 +486,28 @@ bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtua
|
|||||||
switch (virtualDirectory)
|
switch (virtualDirectory)
|
||||||
{
|
{
|
||||||
case PortabilityLayer::VirtualDirectories::kApplicationData:
|
case PortabilityLayer::VirtualDirectories::kApplicationData:
|
||||||
baseDir = m_packagedDir.c_str();
|
baseDir = m_packagedDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kGameData:
|
case PortabilityLayer::VirtualDirectories::kGameData:
|
||||||
baseDir = m_housesDir.c_str();
|
baseDir = m_housesDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kUserData:
|
case PortabilityLayer::VirtualDirectories::kUserData:
|
||||||
baseDir = m_userHousesDir.c_str();
|
baseDir = m_userHousesDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kUserSaves:
|
case PortabilityLayer::VirtualDirectories::kUserSaves:
|
||||||
baseDir = m_userSavesDir.c_str();
|
baseDir = m_userSavesDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kPrefs:
|
case PortabilityLayer::VirtualDirectories::kPrefs:
|
||||||
baseDir = m_prefsDir.c_str();
|
baseDir = m_prefsDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kFonts:
|
case PortabilityLayer::VirtualDirectories::kFonts:
|
||||||
baseDir = m_resourcesDir.c_str();
|
baseDir = m_resourcesDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kHighScores:
|
case PortabilityLayer::VirtualDirectories::kHighScores:
|
||||||
baseDir = m_scoresDir.c_str();
|
baseDir = m_scoresDir.Buffer();
|
||||||
break;
|
break;
|
||||||
case PortabilityLayer::VirtualDirectories::kLogs:
|
case PortabilityLayer::VirtualDirectories::kLogs:
|
||||||
baseDir = m_logsDir.c_str();
|
baseDir = m_logsDir.Buffer();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -507,4 +553,4 @@ bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtua
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpFileSystem_Win32 GpFileSystem_Win32::ms_instance;
|
GpFileSystem_Win32 *GpFileSystem_Win32::ms_instance;
|
||||||
|
@@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
#include "GpCoreDefs.h"
|
#include "GpCoreDefs.h"
|
||||||
#include "GpWindows.h"
|
#include "GpWindows.h"
|
||||||
|
#include "GpString.h"
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class GpFileSystem_Win32 final : public IGpFileSystem
|
class GpFileSystem_Win32 final : public IGpFileSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GpFileSystem_Win32();
|
explicit GpFileSystem_Win32(IGpAllocator *alloc);
|
||||||
|
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
|
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
|
||||||
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) override;
|
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) override;
|
||||||
@@ -25,23 +26,25 @@ public:
|
|||||||
|
|
||||||
const wchar_t *GetBasePath() const;
|
const wchar_t *GetBasePath() const;
|
||||||
|
|
||||||
|
static GpFileSystem_Win32 *CreateInstance(IGpAllocator *alloc);
|
||||||
static GpFileSystem_Win32 *GetInstance();
|
static GpFileSystem_Win32 *GetInstance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool Init();
|
||||||
|
|
||||||
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath);
|
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath);
|
||||||
|
|
||||||
std::wstring m_prefsDir;
|
GpWString m_prefsDir;
|
||||||
std::wstring m_scoresDir;
|
GpWString m_scoresDir;
|
||||||
std::wstring m_packagedDir;
|
GpWString m_packagedDir;
|
||||||
std::wstring m_housesDir;
|
GpWString m_housesDir;
|
||||||
std::wstring m_logsDir;
|
GpWString m_logsDir;
|
||||||
std::wstring m_userHousesDir;
|
GpWString m_userHousesDir;
|
||||||
std::wstring m_userSavesDir;
|
GpWString m_userSavesDir;
|
||||||
std::wstring m_resourcesDir;
|
GpWString m_resourcesDir;
|
||||||
std::wstring m_fontCacheDir;
|
|
||||||
wchar_t m_executablePath[MAX_PATH];
|
wchar_t m_executablePath[MAX_PATH];
|
||||||
|
|
||||||
IGpAllocator *m_alloc;
|
IGpAllocator *m_alloc;
|
||||||
|
|
||||||
static GpFileSystem_Win32 ms_instance;
|
static GpFileSystem_Win32 *ms_instance;
|
||||||
};
|
};
|
||||||
|
@@ -404,6 +404,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
int nArgs;
|
int nArgs;
|
||||||
LPWSTR *cmdLineArgs = CommandLineToArgvW(cmdLine, &nArgs);
|
LPWSTR *cmdLineArgs = CommandLineToArgvW(cmdLine, &nArgs);
|
||||||
|
|
||||||
|
IGpAllocator *alloc = GpAllocator_C::GetInstance();
|
||||||
|
|
||||||
|
// Init file system first since logging may depend on it
|
||||||
|
GpFileSystem_Win32 *fs = GpFileSystem_Win32::CreateInstance(alloc);
|
||||||
|
if (!fs)
|
||||||
|
return -1;
|
||||||
|
|
||||||
for (int i = 1; i < nArgs; i++)
|
for (int i = 1; i < nArgs; i++)
|
||||||
{
|
{
|
||||||
if (!wcscmp(cmdLineArgs[i], L"-diagnostics"))
|
if (!wcscmp(cmdLineArgs[i], L"-diagnostics"))
|
||||||
@@ -411,7 +418,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
}
|
}
|
||||||
|
|
||||||
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
|
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
|
||||||
IGpAllocator *alloc = GpAllocator_C::GetInstance();
|
|
||||||
IGpSystemServices *sysServices = GpSystemServices_Win32::GetInstance();
|
IGpSystemServices *sysServices = GpSystemServices_Win32::GetInstance();
|
||||||
|
|
||||||
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
|
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
|
||||||
@@ -469,5 +475,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
|
|
||||||
LocalFree(cmdLineArgs);
|
LocalFree(cmdLineArgs);
|
||||||
|
|
||||||
|
fs->Destroy();
|
||||||
|
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
@@ -58,33 +58,41 @@ static void AlignedFree(void *ptr)
|
|||||||
class GpAudioBuffer_SDL2 final : public IGpAudioBuffer
|
class GpAudioBuffer_SDL2 final : public IGpAudioBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef int16_t AudioSample_t;
|
||||||
|
|
||||||
static GpAudioBuffer_SDL2 *Create(const void *data, size_t size);
|
static GpAudioBuffer_SDL2 *Create(const void *data, size_t size);
|
||||||
|
|
||||||
void AddRef() override;
|
void AddRef() override;
|
||||||
void Release() override;
|
void Release() override;
|
||||||
|
|
||||||
const void *GetData() const;
|
const AudioSample_t *GetData() const;
|
||||||
size_t GetSize() const;
|
size_t GetSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GpAudioBuffer_SDL2(const void *data, size_t size);
|
GpAudioBuffer_SDL2(const AudioSample_t *data, size_t size);
|
||||||
~GpAudioBuffer_SDL2();
|
~GpAudioBuffer_SDL2();
|
||||||
|
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
const void *m_data;
|
const AudioSample_t *m_data;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
SDL_atomic_t m_count;
|
SDL_atomic_t m_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
GpAudioBuffer_SDL2 *GpAudioBuffer_SDL2::Create(const void *data, size_t size)
|
GpAudioBuffer_SDL2 *GpAudioBuffer_SDL2::Create(const void *data, size_t size)
|
||||||
{
|
{
|
||||||
void *storage = malloc(size + sizeof(GpAudioBuffer_SDL2));
|
size_t baseSize = sizeof(GpAudioBuffer_SDL2) + GP_SYSTEM_MEMORY_ALIGNMENT + 1;
|
||||||
|
baseSize -= baseSize % GP_SYSTEM_MEMORY_ALIGNMENT;
|
||||||
|
void *storage = malloc(size * sizeof(AudioSample_t) + baseSize);
|
||||||
if (!storage)
|
if (!storage)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
void *dataPos = static_cast<uint8_t*>(storage) + sizeof(GpAudioBuffer_SDL2);
|
AudioSample_t *dataPos = reinterpret_cast<AudioSample_t*>(static_cast<uint8_t*>(storage) + baseSize);
|
||||||
memcpy(dataPos, data, size);
|
|
||||||
|
// Convert from u8 to s16
|
||||||
|
const uint8_t *srcData = static_cast<const uint8_t*>(data);
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
dataPos[i] = srcData[i] - 0x80;
|
||||||
|
|
||||||
return new (storage) GpAudioBuffer_SDL2(dataPos, size);
|
return new (storage) GpAudioBuffer_SDL2(dataPos, size);
|
||||||
}
|
}
|
||||||
@@ -102,7 +110,7 @@ void GpAudioBuffer_SDL2::Release()
|
|||||||
this->Destroy();
|
this->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *GpAudioBuffer_SDL2::GetData() const
|
const int16_t *GpAudioBuffer_SDL2::GetData() const
|
||||||
{
|
{
|
||||||
return m_data;
|
return m_data;
|
||||||
}
|
}
|
||||||
@@ -113,7 +121,7 @@ size_t GpAudioBuffer_SDL2::GetSize() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GpAudioBuffer_SDL2::GpAudioBuffer_SDL2(const void *data, size_t size)
|
GpAudioBuffer_SDL2::GpAudioBuffer_SDL2(const int16_t *data, size_t size)
|
||||||
: m_data(data)
|
: m_data(data)
|
||||||
, m_size(size)
|
, m_size(size)
|
||||||
{
|
{
|
||||||
@@ -135,6 +143,7 @@ class GpAudioChannel_SDL2 final : public IGpAudioChannel
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class GpAudioDriver_SDL2;
|
friend class GpAudioDriver_SDL2;
|
||||||
|
typedef GpAudioBuffer_SDL2::AudioSample_t AudioSample_t;
|
||||||
|
|
||||||
GpAudioChannel_SDL2(GpAudioDriver_SDL2_Duration_t latency, GpAudioDriver_SDL2_Duration_t bufferTime, size_t bufferSamplesMax, uint16_t sampleRate);
|
GpAudioChannel_SDL2(GpAudioDriver_SDL2_Duration_t latency, GpAudioDriver_SDL2_Duration_t bufferTime, size_t bufferSamplesMax, uint16_t sampleRate);
|
||||||
~GpAudioChannel_SDL2();
|
~GpAudioChannel_SDL2();
|
||||||
@@ -147,7 +156,7 @@ public:
|
|||||||
void Stop() override;
|
void Stop() override;
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
|
|
||||||
void Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime);
|
void Consume(int16_t *output, size_t sz, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime);
|
||||||
|
|
||||||
static GpAudioChannel_SDL2 *Alloc(GpAudioDriver_SDL2 *driver, GpAudioDriver_SDL2_Duration_t latency, GpAudioDriver_SDL2_Duration_t bufferTime, size_t bufferSamplesMax, uint16_t sampleRate);
|
static GpAudioChannel_SDL2 *Alloc(GpAudioDriver_SDL2 *driver, GpAudioDriver_SDL2_Duration_t latency, GpAudioDriver_SDL2_Duration_t bufferTime, size_t bufferSamplesMax, uint16_t sampleRate);
|
||||||
|
|
||||||
@@ -183,6 +192,9 @@ class GpAudioDriver_SDL2 final : public IGpAudioDriver, public IGpPrefsHandler
|
|||||||
public:
|
public:
|
||||||
friend class GpAudioChannel_SDL2;
|
friend class GpAudioChannel_SDL2;
|
||||||
|
|
||||||
|
typedef GpAudioChannel_SDL2::AudioSample_t AudioSample_t;
|
||||||
|
|
||||||
|
|
||||||
explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties);
|
explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties);
|
||||||
~GpAudioDriver_SDL2();
|
~GpAudioDriver_SDL2();
|
||||||
|
|
||||||
@@ -206,13 +218,14 @@ private:
|
|||||||
|
|
||||||
void MixAudio(void *stream, size_t len);
|
void MixAudio(void *stream, size_t len);
|
||||||
void RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels, size_t maxSamplesToFill, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime);
|
void RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels, size_t maxSamplesToFill, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime);
|
||||||
|
static void AddSamples(AudioSample_t *GP_RESTRICT dest, const AudioSample_t *GP_RESTRICT src, size_t nSamples);
|
||||||
|
|
||||||
GpAudioDriverProperties m_properties;
|
GpAudioDriverProperties m_properties;
|
||||||
IGpMutex *m_mutex;
|
IGpMutex *m_mutex;
|
||||||
IGpMutex *m_mixState;
|
IGpMutex *m_mixState;
|
||||||
|
|
||||||
static const size_t kMaxChannels = 16;
|
static const size_t kMaxChannels = 16;
|
||||||
static const size_t kMixChunkSize = 512;
|
static const size_t kMixChunkSamples = 512;
|
||||||
static const int16_t kMaxAudioVolumeScale = 64;
|
static const int16_t kMaxAudioVolumeScale = 64;
|
||||||
|
|
||||||
GpAudioChannel_SDL2 *m_channels[kMaxChannels];
|
GpAudioChannel_SDL2 *m_channels[kMaxChannels];
|
||||||
@@ -225,7 +238,7 @@ private:
|
|||||||
|
|
||||||
bool m_sdlAudioRunning;
|
bool m_sdlAudioRunning;
|
||||||
|
|
||||||
GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) int16_t m_mixChunk[kMixChunkSize];
|
GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) int16_t m_mixChunk[kMixChunkSamples];
|
||||||
size_t m_mixChunkReadOffset;
|
size_t m_mixChunkReadOffset;
|
||||||
|
|
||||||
int16_t m_audioVolumeScale;
|
int16_t m_audioVolumeScale;
|
||||||
@@ -370,7 +383,7 @@ bool GpAudioChannel_SDL2::Init(GpAudioDriver_SDL2 *driver)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime)
|
void GpAudioChannel_SDL2::Consume(int16_t *output, size_t sz, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime)
|
||||||
{
|
{
|
||||||
m_mutex->Lock();
|
m_mutex->Lock();
|
||||||
|
|
||||||
@@ -380,7 +393,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
|
|
||||||
if (sz <= m_leadingSilence)
|
if (sz <= m_leadingSilence)
|
||||||
{
|
{
|
||||||
memset(output, 0x80, sz);
|
memset(output, 0, sz * sizeof(AudioSample_t));
|
||||||
m_leadingSilence -= sz;
|
m_leadingSilence -= sz;
|
||||||
|
|
||||||
m_isMixing = false;
|
m_isMixing = false;
|
||||||
@@ -392,7 +405,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
size_t leadingSilence = m_leadingSilence;
|
size_t leadingSilence = m_leadingSilence;
|
||||||
if (leadingSilence > 0)
|
if (leadingSilence > 0)
|
||||||
{
|
{
|
||||||
memset(output, 0x80, leadingSilence);
|
memset(output, 0, leadingSilence * sizeof(AudioSample_t));
|
||||||
output += leadingSilence;
|
output += leadingSilence;
|
||||||
sz -= leadingSilence;
|
sz -= leadingSilence;
|
||||||
|
|
||||||
@@ -403,7 +416,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
while (m_numQueuedBuffers > 0)
|
while (m_numQueuedBuffers > 0)
|
||||||
{
|
{
|
||||||
GpAudioBuffer_SDL2 *buffer = m_pendingBuffers[m_nextPendingBufferConsumePos];
|
GpAudioBuffer_SDL2 *buffer = m_pendingBuffers[m_nextPendingBufferConsumePos];
|
||||||
const void *bufferData = buffer->GetData();
|
const int16_t *bufferData = buffer->GetData();
|
||||||
const size_t bufferSize = buffer->GetSize();
|
const size_t bufferSize = buffer->GetSize();
|
||||||
|
|
||||||
assert(m_firstBufferSamplesConsumed < bufferSize);
|
assert(m_firstBufferSamplesConsumed < bufferSize);
|
||||||
@@ -411,7 +424,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
const size_t available = (bufferSize - m_firstBufferSamplesConsumed);
|
const size_t available = (bufferSize - m_firstBufferSamplesConsumed);
|
||||||
if (available <= sz)
|
if (available <= sz)
|
||||||
{
|
{
|
||||||
memcpy(output, static_cast<const uint8_t*>(bufferData) + m_firstBufferSamplesConsumed, available);
|
memcpy(output, bufferData + m_firstBufferSamplesConsumed, available * sizeof(AudioSample_t));
|
||||||
sz -= available;
|
sz -= available;
|
||||||
output += available;
|
output += available;
|
||||||
|
|
||||||
@@ -430,7 +443,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(output, static_cast<const uint8_t*>(bufferData) + m_firstBufferSamplesConsumed, sz);
|
memcpy(output, bufferData + m_firstBufferSamplesConsumed, sz * sizeof(AudioSample_t));
|
||||||
m_firstBufferSamplesConsumed += sz;
|
m_firstBufferSamplesConsumed += sz;
|
||||||
output += sz;
|
output += sz;
|
||||||
sz = 0;
|
sz = 0;
|
||||||
@@ -442,7 +455,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
|
|
||||||
m_mutex->Unlock();
|
m_mutex->Unlock();
|
||||||
|
|
||||||
memset(output, 0x80, sz);
|
memset(output, 0, sz * sizeof(AudioSample_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
GpAudioChannel_SDL2 *GpAudioChannel_SDL2::Alloc(GpAudioDriver_SDL2 *driver, GpAudioDriver_SDL2_Duration_t latency, GpAudioDriver_SDL2_Duration_t bufferTime, size_t bufferSamplesMax, uint16_t sampleRate)
|
GpAudioChannel_SDL2 *GpAudioChannel_SDL2::Alloc(GpAudioDriver_SDL2 *driver, GpAudioDriver_SDL2_Duration_t latency, GpAudioDriver_SDL2_Duration_t bufferTime, size_t bufferSamplesMax, uint16_t sampleRate)
|
||||||
@@ -473,14 +486,14 @@ GpAudioDriver_SDL2::GpAudioDriver_SDL2(const GpAudioDriverProperties &properties
|
|||||||
, m_latency(GpAudioDriver_SDL2_Duration_t::zero())
|
, m_latency(GpAudioDriver_SDL2_Duration_t::zero())
|
||||||
, m_bufferTime(GpAudioDriver_SDL2_Duration_t::zero())
|
, m_bufferTime(GpAudioDriver_SDL2_Duration_t::zero())
|
||||||
, m_sdlAudioRunning(false)
|
, m_sdlAudioRunning(false)
|
||||||
, m_mixChunkReadOffset(kMixChunkSize)
|
, m_mixChunkReadOffset(kMixChunkSamples)
|
||||||
, m_audioVolumeScale(kMaxAudioVolumeScale)
|
, m_audioVolumeScale(kMaxAudioVolumeScale)
|
||||||
|
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < kMaxChannels; i++)
|
for (size_t i = 0; i < kMaxChannels; i++)
|
||||||
m_channels[i] = nullptr;
|
m_channels[i] = nullptr;
|
||||||
|
|
||||||
for (size_t i = 0; i < kMixChunkSize; i++)
|
for (size_t i = 0; i < kMixChunkSamples; i++)
|
||||||
m_mixChunk[i] = 0;
|
m_mixChunk[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +573,7 @@ bool GpAudioDriver_SDL2::Init()
|
|||||||
requestedSpec.channels = 1;
|
requestedSpec.channels = 1;
|
||||||
requestedSpec.format = AUDIO_S16;
|
requestedSpec.format = AUDIO_S16;
|
||||||
requestedSpec.freq = m_properties.m_sampleRate;
|
requestedSpec.freq = m_properties.m_sampleRate;
|
||||||
requestedSpec.samples = kMixChunkSize;
|
requestedSpec.samples = kMixChunkSamples;
|
||||||
requestedSpec.userdata = this;
|
requestedSpec.userdata = this;
|
||||||
|
|
||||||
if (SDL_OpenAudio(&requestedSpec, nullptr))
|
if (SDL_OpenAudio(&requestedSpec, nullptr))
|
||||||
@@ -628,7 +641,7 @@ void GpAudioDriver_SDL2::MixAudio(void *stream, size_t len)
|
|||||||
size_t samplesSinceStart = 0;
|
size_t samplesSinceStart = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
size_t availableInMixChunk = kMixChunkSize - m_mixChunkReadOffset;
|
size_t availableInMixChunk = kMixChunkSamples - m_mixChunkReadOffset;
|
||||||
|
|
||||||
if (availableInMixChunk > samplesRemaining)
|
if (availableInMixChunk > samplesRemaining)
|
||||||
{
|
{
|
||||||
@@ -662,20 +675,21 @@ void GpAudioDriver_SDL2::MixAudio(void *stream, size_t len)
|
|||||||
|
|
||||||
void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels, size_t maxSamplesToFill, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime)
|
void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels, size_t maxSamplesToFill, GpAudioDriver_SDL2_TimePoint_t mixStartTime, GpAudioDriver_SDL2_TimePoint_t mixEndTime)
|
||||||
{
|
{
|
||||||
uint8_t audioMixBufferUnaligned[kMixChunkSize + GP_SYSTEM_MEMORY_ALIGNMENT];
|
uint8_t audioMixBufferUnaligned[kMixChunkSamples * sizeof(AudioSample_t) + GP_SYSTEM_MEMORY_ALIGNMENT];
|
||||||
uint8_t *audioMixBuffer = audioMixBufferUnaligned;
|
uint8_t *audioMixBufferBytes = audioMixBufferUnaligned;
|
||||||
|
|
||||||
{
|
{
|
||||||
uintptr_t bufferPtr = reinterpret_cast<uintptr_t>(audioMixBuffer);
|
uintptr_t bufferPtr = reinterpret_cast<uintptr_t>(audioMixBufferBytes);
|
||||||
size_t alignPadding = GP_SYSTEM_MEMORY_ALIGNMENT - (bufferPtr % GP_SYSTEM_MEMORY_ALIGNMENT);
|
size_t alignPadding = GP_SYSTEM_MEMORY_ALIGNMENT - (bufferPtr % GP_SYSTEM_MEMORY_ALIGNMENT);
|
||||||
audioMixBuffer += alignPadding;
|
audioMixBufferBytes += alignPadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioSample_t *audioMixBuffer = reinterpret_cast<AudioSample_t*>(audioMixBufferBytes);
|
||||||
bool noAudio = true;
|
bool noAudio = true;
|
||||||
|
|
||||||
const int16_t audioVolumeScale = m_audioVolumeScale;
|
const int16_t audioVolumeScale = m_audioVolumeScale;
|
||||||
|
|
||||||
size_t samplesToFill = kMixChunkSize;
|
size_t samplesToFill = kMixChunkSamples;
|
||||||
if (samplesToFill > maxSamplesToFill)
|
if (samplesToFill > maxSamplesToFill)
|
||||||
{
|
{
|
||||||
m_mixChunkReadOffset += samplesToFill - maxSamplesToFill;
|
m_mixChunkReadOffset += samplesToFill - maxSamplesToFill;
|
||||||
@@ -684,8 +698,7 @@ void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, siz
|
|||||||
else
|
else
|
||||||
m_mixChunkReadOffset = 0;
|
m_mixChunkReadOffset = 0;
|
||||||
|
|
||||||
int16_t *mixChunkStart = m_mixChunk + m_mixChunkReadOffset;
|
AudioSample_t *mixChunkStart = m_mixChunk + m_mixChunkReadOffset;
|
||||||
int16_t audioNormalizeShift = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < numChannels; i++)
|
for (size_t i = 0; i < numChannels; i++)
|
||||||
{
|
{
|
||||||
@@ -694,27 +707,27 @@ void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, siz
|
|||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
noAudio = false;
|
noAudio = false;
|
||||||
audioNormalizeShift = 0x80;
|
memcpy(mixChunkStart, audioMixBuffer, samplesToFill * sizeof(AudioSample_t));
|
||||||
for (size_t j = 0; j < samplesToFill; j++)
|
|
||||||
mixChunkStart[j] = static_cast<int16_t>(audioMixBuffer[j]);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
AddSamples(mixChunkStart, audioMixBuffer, samplesToFill);
|
||||||
audioNormalizeShift += 0x80;
|
|
||||||
for (size_t j = 0; j < samplesToFill; j++)
|
|
||||||
mixChunkStart[j] += static_cast<int16_t>(audioMixBuffer[j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noAudio)
|
if (noAudio)
|
||||||
memset(mixChunkStart, 0, samplesToFill * sizeof(mixChunkStart[0]));
|
memset(mixChunkStart, 0, samplesToFill * sizeof(AudioSample_t));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < samplesToFill; i++)
|
for (size_t i = 0; i < samplesToFill; i++)
|
||||||
mixChunkStart[i] = (mixChunkStart[i] - audioNormalizeShift) * audioVolumeScale;
|
mixChunkStart[i] *= audioVolumeScale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GpAudioDriver_SDL2::AddSamples(AudioSample_t *GP_RESTRICT dest, const AudioSample_t *GP_RESTRICT src, size_t nSamples)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < nSamples; i++)
|
||||||
|
dest[i] += src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GpAudioDriver_SDL2_TimePoint_t GpAudioDriver_SDL2::GetCurrentTime()
|
GpAudioDriver_SDL2_TimePoint_t GpAudioDriver_SDL2::GetCurrentTime()
|
||||||
{
|
{
|
||||||
|
@@ -37,6 +37,12 @@ IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverPrope
|
|||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
|
IGpAllocator *alloc = GpAllocator_C::GetInstance();
|
||||||
|
|
||||||
|
GpFileSystem_Win32 *fs = GpFileSystem_Win32::CreateInstance(alloc);
|
||||||
|
if (!fs)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0)
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -57,7 +63,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
|
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
|
||||||
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
|
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
|
||||||
|
|
||||||
drivers->SetDriver<GpDriverIDs::kFileSystem>(GpFileSystem_Win32::GetInstance());
|
drivers->SetDriver<GpDriverIDs::kFileSystem>(fs);
|
||||||
drivers->SetDriver<GpDriverIDs::kSystemServices>(GpSystemServices_Win32::GetInstance());
|
drivers->SetDriver<GpDriverIDs::kSystemServices>(GpSystemServices_Win32::GetInstance());
|
||||||
drivers->SetDriver<GpDriverIDs::kLog>(GpLogDriver_Win32::GetInstance());
|
drivers->SetDriver<GpDriverIDs::kLog>(GpLogDriver_Win32::GetInstance());
|
||||||
drivers->SetDriver<GpDriverIDs::kAlloc>(GpAllocator_C::GetInstance());
|
drivers->SetDriver<GpDriverIDs::kAlloc>(GpAllocator_C::GetInstance());
|
||||||
@@ -88,7 +94,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals;
|
g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals;
|
||||||
g_gpGlobalConfig.m_logger = logger;
|
g_gpGlobalConfig.m_logger = logger;
|
||||||
g_gpGlobalConfig.m_systemServices = GpSystemServices_Win32::GetInstance();
|
g_gpGlobalConfig.m_systemServices = GpSystemServices_Win32::GetInstance();
|
||||||
g_gpGlobalConfig.m_allocator = GpAllocator_C::GetInstance();
|
g_gpGlobalConfig.m_allocator = alloc;
|
||||||
|
|
||||||
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2);
|
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2);
|
||||||
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
|
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
|
||||||
@@ -105,5 +111,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
|
|
||||||
LocalFree(cmdLineArgs);
|
LocalFree(cmdLineArgs);
|
||||||
|
|
||||||
|
fs->Destroy();
|
||||||
|
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
@@ -13,11 +13,13 @@
|
|||||||
#define GP_ALIGNED(n) __declspec(align(n))
|
#define GP_ALIGNED(n) __declspec(align(n))
|
||||||
#else
|
#else
|
||||||
#define GP_ALIGNED(n) __attribute__((aligned(n)))
|
#define GP_ALIGNED(n) __attribute__((aligned(n)))
|
||||||
|
#define GP_RESTRICT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GP_IS_CPP11
|
#if GP_IS_CPP11
|
||||||
#define GP_DELETED = delete
|
#define GP_DELETED = delete
|
||||||
#define GP_STATIC_ASSERT(n) static_assert((n), "Static assert failed: " #n)
|
#define GP_STATIC_ASSERT(n) static_assert((n), "Static assert failed: " #n)
|
||||||
|
#define GP_RESTRICT __restrict
|
||||||
#else
|
#else
|
||||||
#ifndef nullptr
|
#ifndef nullptr
|
||||||
#define nullptr 0
|
#define nullptr 0
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GP_DELETED
|
#define GP_DELETED
|
||||||
|
#define GP_RESTRICT
|
||||||
|
|
||||||
template<bool TCondition>
|
template<bool TCondition>
|
||||||
struct __GpStaticAssertHelper
|
struct __GpStaticAssertHelper
|
||||||
|
150
GpCommon/GpString.h
Normal file
150
GpCommon/GpString.h
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GpVector.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
class GpString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit GpString(IGpAllocator *alloc);
|
||||||
|
GpString(GpString<TChar> &&other);
|
||||||
|
|
||||||
|
bool Set(const TChar *str);
|
||||||
|
bool Set(const TChar *str, size_t len);
|
||||||
|
bool Set(const GpString<TChar> &other);
|
||||||
|
|
||||||
|
bool Append(const TChar *str);
|
||||||
|
bool Append(const TChar *str, size_t len);
|
||||||
|
bool Append(const GpString<TChar> &other);
|
||||||
|
|
||||||
|
TChar *Buffer();
|
||||||
|
const TChar *Buffer() const ;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const size_t kStaticSize = 32;
|
||||||
|
|
||||||
|
GpVector<TChar, kStaticSize> m_chars;
|
||||||
|
size_t m_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GpString<char> GpCString;
|
||||||
|
typedef GpString<wchar_t> GpWString;
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
GpString<TChar>::GpString(IGpAllocator *alloc)
|
||||||
|
: m_chars(alloc)
|
||||||
|
, m_length(0)
|
||||||
|
{
|
||||||
|
(void)m_chars.Resize(1);
|
||||||
|
m_chars[0] = static_cast<TChar>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
GpString<TChar>::GpString(GpString<TChar> &&other)
|
||||||
|
: m_chars(static_cast<GpVector<TChar, kStaticSize>&&>(other.m_chars))
|
||||||
|
, m_length(other.m_length)
|
||||||
|
{
|
||||||
|
other.m_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
bool GpString<TChar>::Set(const TChar *str)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
while (str[len] != static_cast<TChar>(0))
|
||||||
|
len++;
|
||||||
|
|
||||||
|
return this->Set(str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
bool GpString<TChar>::Set(const TChar *str, size_t len)
|
||||||
|
{
|
||||||
|
if (!m_chars.ResizeNoConstruct(len + 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TChar *chars = m_chars.Buffer();
|
||||||
|
memcpy(chars, str, sizeof(TChar) * len);
|
||||||
|
chars[len] = static_cast<TChar>(0);
|
||||||
|
|
||||||
|
m_length = len;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
bool GpString<TChar>::Set(const GpString<TChar> &other)
|
||||||
|
{
|
||||||
|
if (&other == this)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return this->Set(other.Buffer(), other.m_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
bool GpString<TChar>::Append(const TChar *str)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
while (str[len] != static_cast<TChar>(0))
|
||||||
|
len++;
|
||||||
|
|
||||||
|
return this->Append(str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
bool GpString<TChar>::Append(const TChar *str, size_t len)
|
||||||
|
{
|
||||||
|
// This is a special path in case we're appending the string to itself and the resize relocates the buffer
|
||||||
|
if (len == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
assert(str != this->Buffer());
|
||||||
|
|
||||||
|
if (!m_chars.ResizeNoConstruct(m_length + len + 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(m_chars.Buffer() + m_length, str, sizeof(TChar) * len);
|
||||||
|
m_chars[m_length + len] = static_cast<TChar>(0);
|
||||||
|
|
||||||
|
m_length += len;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
bool GpString<TChar>::Append(const GpString<TChar> &other)
|
||||||
|
{
|
||||||
|
// This is a special path in case we're appending the string to itself and the resize relocates the buffer
|
||||||
|
if (other.m_length == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!m_chars.ResizeNoConstruct(m_length + other.m_length))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(m_chars.Buffer() + m_length, other.Buffer(), sizeof(TChar) * other.m_length);
|
||||||
|
m_chars[m_length + other.m_length] = static_cast<TChar>(0);
|
||||||
|
|
||||||
|
m_length += other.m_length;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
TChar *GpString<TChar>::Buffer()
|
||||||
|
{
|
||||||
|
return m_chars.Buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TChar>
|
||||||
|
const TChar *GpString<TChar>::Buffer() const
|
||||||
|
{
|
||||||
|
return m_chars.Buffer();
|
||||||
|
}
|
230
GpCommon/GpVector.h
Normal file
230
GpCommon/GpVector.h
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreDefs.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct IGpAllocator;
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
class GpVectorStaticData
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) uint8_t m_staticElementData[sizeof(T) * TStaticSize];
|
||||||
|
|
||||||
|
T *GetStaticElements();
|
||||||
|
const T *GetStaticElements() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class GpVectorStaticData<T, 0>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
T *GetStaticElements();
|
||||||
|
const T *GetStaticElements() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize = 0>
|
||||||
|
class GpVector : public GpVectorStaticData<T, TStaticSize>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit GpVector(IGpAllocator *alloc);
|
||||||
|
GpVector(GpVector<T, TStaticSize> &&other);
|
||||||
|
~GpVector();
|
||||||
|
|
||||||
|
T &operator[](size_t index);
|
||||||
|
const T &operator[](size_t index) const;
|
||||||
|
|
||||||
|
bool Resize(size_t newSize);
|
||||||
|
bool ResizeNoConstruct(size_t newSize);
|
||||||
|
|
||||||
|
T *Buffer();
|
||||||
|
const T *Buffer() const;
|
||||||
|
|
||||||
|
const size_t Count() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GpVector(const GpVector<T, TStaticSize> &other) GP_DELETED;
|
||||||
|
|
||||||
|
static const size_t kStaticSize = TStaticSize;
|
||||||
|
|
||||||
|
T *m_elements;
|
||||||
|
size_t m_capacity;
|
||||||
|
size_t m_count;
|
||||||
|
IGpAllocator *m_alloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <cassert>
|
||||||
|
#include "IGpAllocator.h"
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
T *GpVectorStaticData<T, TStaticSize>::GetStaticElements()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(this->m_staticElementData);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
const T *GpVectorStaticData<T, TStaticSize>::GetStaticElements() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const T*>(this->m_staticElementData);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T *GpVectorStaticData<T, 0>::GetStaticElements()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
const T *GpVectorStaticData<T, 0>::GetStaticElements() const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GpVector
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
GpVector<T, TStaticSize>::GpVector(IGpAllocator *alloc)
|
||||||
|
: m_elements(this->GetStaticElements())
|
||||||
|
, m_capacity(TStaticSize)
|
||||||
|
, m_count(0)
|
||||||
|
, m_alloc(alloc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
GpVector<T, TStaticSize>::GpVector(GpVector<T, TStaticSize> &&other)
|
||||||
|
: m_elements(other.m_elements)
|
||||||
|
, m_capacity(other.m_capacity)
|
||||||
|
, m_count(other.m_count)
|
||||||
|
, m_alloc(other.m_alloc)
|
||||||
|
{
|
||||||
|
if (m_capacity <= TStaticSize)
|
||||||
|
{
|
||||||
|
const size_t count = m_count;
|
||||||
|
T *elements = this->GetStaticElements();
|
||||||
|
const T *srcElements = other.m_elements;
|
||||||
|
m_elements = elements;
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
new (m_elements + i) T(static_cast<T&&>(other.m_elements));
|
||||||
|
}
|
||||||
|
|
||||||
|
other.m_count = 0;
|
||||||
|
other.m_capacity = 0;
|
||||||
|
other.m_elements = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
GpVector<T, TStaticSize>::~GpVector()
|
||||||
|
{
|
||||||
|
T *elements = m_elements;
|
||||||
|
size_t remaining = m_count;
|
||||||
|
|
||||||
|
while (remaining > 0)
|
||||||
|
{
|
||||||
|
remaining--;
|
||||||
|
elements[remaining].~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_capacity > TStaticSize)
|
||||||
|
{
|
||||||
|
m_alloc->Release(m_elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
T &GpVector<T, TStaticSize>::operator[](size_t index)
|
||||||
|
{
|
||||||
|
assert(index <= m_count);
|
||||||
|
return m_elements[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
const T &GpVector<T, TStaticSize>::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
assert(index <= m_count);
|
||||||
|
return m_elements[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
bool GpVector<T, TStaticSize>::Resize(size_t newSize)
|
||||||
|
{
|
||||||
|
const size_t oldCount = m_count;
|
||||||
|
|
||||||
|
if (!ResizeNoConstruct(newSize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = oldCount; i < newSize; i++)
|
||||||
|
new (m_elements + i) T();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
bool GpVector<T, TStaticSize>::ResizeNoConstruct(size_t newSize)
|
||||||
|
{
|
||||||
|
T *elements = m_elements;
|
||||||
|
|
||||||
|
if (newSize <= m_count)
|
||||||
|
{
|
||||||
|
size_t count = m_count;
|
||||||
|
while (count > newSize)
|
||||||
|
{
|
||||||
|
count--;
|
||||||
|
m_elements[count].~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_count = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSize <= m_capacity)
|
||||||
|
{
|
||||||
|
m_count = newSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t newCapacity = newSize;
|
||||||
|
assert(newCapacity > kStaticSize);
|
||||||
|
|
||||||
|
T *newElements = static_cast<T*>(m_alloc->Alloc(newCapacity * sizeof(T)));
|
||||||
|
if (!newElements)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const size_t oldCount = m_count;
|
||||||
|
for (size_t i = 0; i < oldCount; i++)
|
||||||
|
new (newElements + i) T(static_cast<T&&>(elements[i]));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < oldCount; i++)
|
||||||
|
elements[oldCount - 1 - i].~T();
|
||||||
|
|
||||||
|
if (m_capacity > kStaticSize)
|
||||||
|
m_alloc->Release(m_elements);
|
||||||
|
|
||||||
|
m_elements = newElements;
|
||||||
|
m_capacity = newCapacity;
|
||||||
|
m_count = newSize;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
const size_t GpVector<T, TStaticSize>::Count() const
|
||||||
|
{
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
T *GpVector<T, TStaticSize>::Buffer()
|
||||||
|
{
|
||||||
|
return m_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, size_t TStaticSize>
|
||||||
|
const T *GpVector<T, TStaticSize>::Buffer() const
|
||||||
|
{
|
||||||
|
return m_elements;
|
||||||
|
}
|
Reference in New Issue
Block a user