diff --git a/Aerofoil/Aerofoil.vcxproj b/Aerofoil/Aerofoil.vcxproj
index 9a46344..3307793 100644
--- a/Aerofoil/Aerofoil.vcxproj
+++ b/Aerofoil/Aerofoil.vcxproj
@@ -103,6 +103,8 @@
+
+
diff --git a/Aerofoil/Aerofoil.vcxproj.filters b/Aerofoil/Aerofoil.vcxproj.filters
index 6e8d027..6c42a88 100644
--- a/Aerofoil/Aerofoil.vcxproj.filters
+++ b/Aerofoil/Aerofoil.vcxproj.filters
@@ -93,6 +93,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/Aerofoil/GpFileSystem_Win32.cpp b/Aerofoil/GpFileSystem_Win32.cpp
index 485fbcc..14e98ed 100644
--- a/Aerofoil/GpFileSystem_Win32.cpp
+++ b/Aerofoil/GpFileSystem_Win32.cpp
@@ -7,7 +7,7 @@
#include "IGpAllocator.h"
#include "IGpDirectoryCursor.h"
-#include
+
#include
#include
#include
@@ -105,49 +105,70 @@ GpDirectoryCursor_Win32::~GpDirectoryCursor_Win32()
FindClose(m_handle);
}
-GpFileSystem_Win32::GpFileSystem_Win32()
- : m_alloc(GpAllocator_C::GetInstance())
+GpFileSystem_Win32::GpFileSystem_Win32(IGpAllocator *alloc)
+ : 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;
+}
+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)))
+ if (FAILED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &docsPath)))
+ return false;
+
+ if (!m_prefsDir.Set(docsPath))
{
- try
- {
- m_prefsDir = docsPath;
- }
- catch(...)
- {
- CoTaskMemFree(docsPath);
- throw;
- }
-
- m_prefsDir.append(L"\\" GP_APPLICATION_NAME_W);
-
- m_userHousesDir = m_prefsDir + L"\\Houses";
- m_userSavesDir = m_prefsDir + L"\\SavedGames";
- m_scoresDir = m_prefsDir + L"\\Scores";
- m_logsDir = m_prefsDir + L"\\Logs";
- m_fontCacheDir = m_prefsDir + L"\\FontCache";
-
- CreateDirectoryW(m_prefsDir.c_str(), nullptr);
- CreateDirectoryW(m_scoresDir.c_str(), nullptr);
- 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"\\");
- m_scoresDir.append(L"\\");
- m_userHousesDir.append(L"\\");
- m_userSavesDir.append(L"\\");
- m_logsDir.append(L"\\");
- m_fontCacheDir.append(L"\\");
- m_resourcesDir.append(L"\\");
+ CoTaskMemFree(docsPath);
+ return false;
}
+ CoTaskMemFree(docsPath);
+
+ if (!m_prefsDir.Append(L"\\" GP_APPLICATION_NAME_W))
+ return false;
+
+ if (!m_userHousesDir.Set(m_prefsDir) || !m_userHousesDir.Append(L"\\Houses"))
+ return false;
+
+ if (!m_userSavesDir.Set(m_prefsDir) || !m_userSavesDir.Append(L"\\SavedGames"))
+ return false;
+
+ if (!m_scoresDir.Set(m_prefsDir) || !m_scoresDir.Append(L"\\Scores"))
+ return false;
+
+ 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);
if (modulePathSize == MAX_PATH || modulePathSize == 0)
m_executablePath[0] = 0;
@@ -182,12 +203,19 @@ GpFileSystem_Win32::GpFileSystem_Win32()
currentPathLength--;
}
- if (currentPathLength > 0)
- {
- m_packagedDir = std::wstring(m_executablePath) + L"Packaged\\";
- m_housesDir = std::wstring(m_executablePath) + L"Packaged\\Houses\\";
- m_resourcesDir = std::wstring(m_executablePath) + L"Resources\\";
- }
+ if (currentPathLength == 0)
+ return false;
+
+ if (!m_packagedDir.Set(m_executablePath) || !m_packagedDir.Append(L"Packaged\\"))
+ 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)
@@ -428,9 +456,27 @@ const wchar_t *GpFileSystem_Win32::GetBasePath() const
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()
{
- return &ms_instance;
+ return ms_instance;
}
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)
{
case PortabilityLayer::VirtualDirectories::kApplicationData:
- baseDir = m_packagedDir.c_str();
+ baseDir = m_packagedDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kGameData:
- baseDir = m_housesDir.c_str();
+ baseDir = m_housesDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kUserData:
- baseDir = m_userHousesDir.c_str();
+ baseDir = m_userHousesDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kUserSaves:
- baseDir = m_userSavesDir.c_str();
+ baseDir = m_userSavesDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kPrefs:
- baseDir = m_prefsDir.c_str();
+ baseDir = m_prefsDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kFonts:
- baseDir = m_resourcesDir.c_str();
+ baseDir = m_resourcesDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kHighScores:
- baseDir = m_scoresDir.c_str();
+ baseDir = m_scoresDir.Buffer();
break;
case PortabilityLayer::VirtualDirectories::kLogs:
- baseDir = m_logsDir.c_str();
+ baseDir = m_logsDir.Buffer();
break;
default:
return false;
@@ -507,4 +553,4 @@ bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtua
return true;
}
-GpFileSystem_Win32 GpFileSystem_Win32::ms_instance;
+GpFileSystem_Win32 *GpFileSystem_Win32::ms_instance;
diff --git a/Aerofoil/GpFileSystem_Win32.h b/Aerofoil/GpFileSystem_Win32.h
index 45acb89..8b75eb7 100644
--- a/Aerofoil/GpFileSystem_Win32.h
+++ b/Aerofoil/GpFileSystem_Win32.h
@@ -4,13 +4,14 @@
#include "GpCoreDefs.h"
#include "GpWindows.h"
-
-#include
+#include "GpString.h"
class GpFileSystem_Win32 final : public IGpFileSystem
{
public:
- GpFileSystem_Win32();
+ explicit GpFileSystem_Win32(IGpAllocator *alloc);
+
+ void Destroy();
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) override;
@@ -25,23 +26,25 @@ public:
const wchar_t *GetBasePath() const;
+ static GpFileSystem_Win32 *CreateInstance(IGpAllocator *alloc);
static GpFileSystem_Win32 *GetInstance();
private:
+ bool Init();
+
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath);
- std::wstring m_prefsDir;
- std::wstring m_scoresDir;
- std::wstring m_packagedDir;
- std::wstring m_housesDir;
- std::wstring m_logsDir;
- std::wstring m_userHousesDir;
- std::wstring m_userSavesDir;
- std::wstring m_resourcesDir;
- std::wstring m_fontCacheDir;
+ GpWString m_prefsDir;
+ GpWString m_scoresDir;
+ GpWString m_packagedDir;
+ GpWString m_housesDir;
+ GpWString m_logsDir;
+ GpWString m_userHousesDir;
+ GpWString m_userSavesDir;
+ GpWString m_resourcesDir;
wchar_t m_executablePath[MAX_PATH];
IGpAllocator *m_alloc;
- static GpFileSystem_Win32 ms_instance;
+ static GpFileSystem_Win32 *ms_instance;
};
diff --git a/Aerofoil/GpMain_Win32.cpp b/Aerofoil/GpMain_Win32.cpp
index 2343ac7..207d111 100644
--- a/Aerofoil/GpMain_Win32.cpp
+++ b/Aerofoil/GpMain_Win32.cpp
@@ -404,6 +404,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
int 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++)
{
if (!wcscmp(cmdLineArgs[i], L"-diagnostics"))
@@ -411,7 +418,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
- IGpAllocator *alloc = GpAllocator_C::GetInstance();
IGpSystemServices *sysServices = GpSystemServices_Win32::GetInstance();
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
@@ -469,5 +475,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
LocalFree(cmdLineArgs);
+ fs->Destroy();
+
return returnCode;
}
diff --git a/AerofoilSDL/GpAudioDriver_SDL2.cpp b/AerofoilSDL/GpAudioDriver_SDL2.cpp
index 070697d..a01253d 100644
--- a/AerofoilSDL/GpAudioDriver_SDL2.cpp
+++ b/AerofoilSDL/GpAudioDriver_SDL2.cpp
@@ -58,33 +58,41 @@ static void AlignedFree(void *ptr)
class GpAudioBuffer_SDL2 final : public IGpAudioBuffer
{
public:
+ typedef int16_t AudioSample_t;
+
static GpAudioBuffer_SDL2 *Create(const void *data, size_t size);
void AddRef() override;
void Release() override;
- const void *GetData() const;
+ const AudioSample_t *GetData() const;
size_t GetSize() const;
private:
- GpAudioBuffer_SDL2(const void *data, size_t size);
+ GpAudioBuffer_SDL2(const AudioSample_t *data, size_t size);
~GpAudioBuffer_SDL2();
void Destroy();
- const void *m_data;
+ const AudioSample_t *m_data;
size_t m_size;
SDL_atomic_t m_count;
};
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)
return nullptr;
- void *dataPos = static_cast(storage) + sizeof(GpAudioBuffer_SDL2);
- memcpy(dataPos, data, size);
+ AudioSample_t *dataPos = reinterpret_cast(static_cast(storage) + baseSize);
+
+ // Convert from u8 to s16
+ const uint8_t *srcData = static_cast(data);
+ for (size_t i = 0; i < size; i++)
+ dataPos[i] = srcData[i] - 0x80;
return new (storage) GpAudioBuffer_SDL2(dataPos, size);
}
@@ -102,7 +110,7 @@ void GpAudioBuffer_SDL2::Release()
this->Destroy();
}
-const void *GpAudioBuffer_SDL2::GetData() const
+const int16_t *GpAudioBuffer_SDL2::GetData() const
{
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_size(size)
{
@@ -135,6 +143,7 @@ class GpAudioChannel_SDL2 final : public IGpAudioChannel
{
public:
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();
@@ -147,7 +156,7 @@ public:
void Stop() 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);
@@ -183,6 +192,9 @@ class GpAudioDriver_SDL2 final : public IGpAudioDriver, public IGpPrefsHandler
public:
friend class GpAudioChannel_SDL2;
+ typedef GpAudioChannel_SDL2::AudioSample_t AudioSample_t;
+
+
explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties);
~GpAudioDriver_SDL2();
@@ -206,13 +218,14 @@ private:
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);
+ static void AddSamples(AudioSample_t *GP_RESTRICT dest, const AudioSample_t *GP_RESTRICT src, size_t nSamples);
GpAudioDriverProperties m_properties;
IGpMutex *m_mutex;
IGpMutex *m_mixState;
static const size_t kMaxChannels = 16;
- static const size_t kMixChunkSize = 512;
+ static const size_t kMixChunkSamples = 512;
static const int16_t kMaxAudioVolumeScale = 64;
GpAudioChannel_SDL2 *m_channels[kMaxChannels];
@@ -225,7 +238,7 @@ private:
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;
int16_t m_audioVolumeScale;
@@ -370,7 +383,7 @@ bool GpAudioChannel_SDL2::Init(GpAudioDriver_SDL2 *driver)
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();
@@ -380,7 +393,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
if (sz <= m_leadingSilence)
{
- memset(output, 0x80, sz);
+ memset(output, 0, sz * sizeof(AudioSample_t));
m_leadingSilence -= sz;
m_isMixing = false;
@@ -392,7 +405,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
size_t leadingSilence = m_leadingSilence;
if (leadingSilence > 0)
{
- memset(output, 0x80, leadingSilence);
+ memset(output, 0, leadingSilence * sizeof(AudioSample_t));
output += leadingSilence;
sz -= leadingSilence;
@@ -403,7 +416,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
while (m_numQueuedBuffers > 0)
{
GpAudioBuffer_SDL2 *buffer = m_pendingBuffers[m_nextPendingBufferConsumePos];
- const void *bufferData = buffer->GetData();
+ const int16_t *bufferData = buffer->GetData();
const size_t bufferSize = buffer->GetSize();
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);
if (available <= sz)
{
- memcpy(output, static_cast(bufferData) + m_firstBufferSamplesConsumed, available);
+ memcpy(output, bufferData + m_firstBufferSamplesConsumed, available * sizeof(AudioSample_t));
sz -= available;
output += available;
@@ -430,7 +443,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
}
else
{
- memcpy(output, static_cast(bufferData) + m_firstBufferSamplesConsumed, sz);
+ memcpy(output, bufferData + m_firstBufferSamplesConsumed, sz * sizeof(AudioSample_t));
m_firstBufferSamplesConsumed += sz;
output += sz;
sz = 0;
@@ -442,7 +455,7 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
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)
@@ -473,14 +486,14 @@ GpAudioDriver_SDL2::GpAudioDriver_SDL2(const GpAudioDriverProperties &properties
, m_latency(GpAudioDriver_SDL2_Duration_t::zero())
, m_bufferTime(GpAudioDriver_SDL2_Duration_t::zero())
, m_sdlAudioRunning(false)
- , m_mixChunkReadOffset(kMixChunkSize)
+ , m_mixChunkReadOffset(kMixChunkSamples)
, m_audioVolumeScale(kMaxAudioVolumeScale)
{
for (size_t i = 0; i < kMaxChannels; i++)
m_channels[i] = nullptr;
- for (size_t i = 0; i < kMixChunkSize; i++)
+ for (size_t i = 0; i < kMixChunkSamples; i++)
m_mixChunk[i] = 0;
}
@@ -560,7 +573,7 @@ bool GpAudioDriver_SDL2::Init()
requestedSpec.channels = 1;
requestedSpec.format = AUDIO_S16;
requestedSpec.freq = m_properties.m_sampleRate;
- requestedSpec.samples = kMixChunkSize;
+ requestedSpec.samples = kMixChunkSamples;
requestedSpec.userdata = this;
if (SDL_OpenAudio(&requestedSpec, nullptr))
@@ -628,7 +641,7 @@ void GpAudioDriver_SDL2::MixAudio(void *stream, size_t len)
size_t samplesSinceStart = 0;
for (;;)
{
- size_t availableInMixChunk = kMixChunkSize - m_mixChunkReadOffset;
+ size_t availableInMixChunk = kMixChunkSamples - m_mixChunkReadOffset;
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)
{
- uint8_t audioMixBufferUnaligned[kMixChunkSize + GP_SYSTEM_MEMORY_ALIGNMENT];
- uint8_t *audioMixBuffer = audioMixBufferUnaligned;
+ uint8_t audioMixBufferUnaligned[kMixChunkSamples * sizeof(AudioSample_t) + GP_SYSTEM_MEMORY_ALIGNMENT];
+ uint8_t *audioMixBufferBytes = audioMixBufferUnaligned;
{
- uintptr_t bufferPtr = reinterpret_cast(audioMixBuffer);
+ uintptr_t bufferPtr = reinterpret_cast(audioMixBufferBytes);
size_t alignPadding = GP_SYSTEM_MEMORY_ALIGNMENT - (bufferPtr % GP_SYSTEM_MEMORY_ALIGNMENT);
- audioMixBuffer += alignPadding;
+ audioMixBufferBytes += alignPadding;
}
+ AudioSample_t *audioMixBuffer = reinterpret_cast(audioMixBufferBytes);
bool noAudio = true;
const int16_t audioVolumeScale = m_audioVolumeScale;
- size_t samplesToFill = kMixChunkSize;
+ size_t samplesToFill = kMixChunkSamples;
if (samplesToFill > maxSamplesToFill)
{
m_mixChunkReadOffset += samplesToFill - maxSamplesToFill;
@@ -684,8 +698,7 @@ void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, siz
else
m_mixChunkReadOffset = 0;
- int16_t *mixChunkStart = m_mixChunk + m_mixChunkReadOffset;
- int16_t audioNormalizeShift = 0;
+ AudioSample_t *mixChunkStart = m_mixChunk + m_mixChunkReadOffset;
for (size_t i = 0; i < numChannels; i++)
{
@@ -694,27 +707,27 @@ void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, siz
if (i == 0)
{
noAudio = false;
- audioNormalizeShift = 0x80;
- for (size_t j = 0; j < samplesToFill; j++)
- mixChunkStart[j] = static_cast(audioMixBuffer[j]);
+ memcpy(mixChunkStart, audioMixBuffer, samplesToFill * sizeof(AudioSample_t));
}
else
- {
- audioNormalizeShift += 0x80;
- for (size_t j = 0; j < samplesToFill; j++)
- mixChunkStart[j] += static_cast(audioMixBuffer[j]);
- }
+ AddSamples(mixChunkStart, audioMixBuffer, samplesToFill);
}
if (noAudio)
- memset(mixChunkStart, 0, samplesToFill * sizeof(mixChunkStart[0]));
+ memset(mixChunkStart, 0, samplesToFill * sizeof(AudioSample_t));
else
{
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()
{
diff --git a/AerofoilSDL/GpMain_SDL_Win32.cpp b/AerofoilSDL/GpMain_SDL_Win32.cpp
index 39a0198..0220c7a 100644
--- a/AerofoilSDL/GpMain_SDL_Win32.cpp
+++ b/AerofoilSDL/GpMain_SDL_Win32.cpp
@@ -37,6 +37,12 @@ IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverPrope
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)
return -1;
@@ -57,7 +63,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
- drivers->SetDriver(GpFileSystem_Win32::GetInstance());
+ drivers->SetDriver(fs);
drivers->SetDriver(GpSystemServices_Win32::GetInstance());
drivers->SetDriver(GpLogDriver_Win32::GetInstance());
drivers->SetDriver(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_logger = logger;
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);
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
@@ -105,5 +111,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
LocalFree(cmdLineArgs);
+ fs->Destroy();
+
return returnCode;
}
diff --git a/Common/CoreDefs.h b/Common/CoreDefs.h
index 8e597ed..d74ccae 100644
--- a/Common/CoreDefs.h
+++ b/Common/CoreDefs.h
@@ -13,11 +13,13 @@
#define GP_ALIGNED(n) __declspec(align(n))
#else
#define GP_ALIGNED(n) __attribute__((aligned(n)))
+#define GP_RESTRICT
#endif
#if GP_IS_CPP11
#define GP_DELETED = delete
#define GP_STATIC_ASSERT(n) static_assert((n), "Static assert failed: " #n)
+#define GP_RESTRICT __restrict
#else
#ifndef nullptr
#define nullptr 0
@@ -32,6 +34,7 @@
#endif
#define GP_DELETED
+#define GP_RESTRICT
template
struct __GpStaticAssertHelper
diff --git a/GpCommon/GpString.h b/GpCommon/GpString.h
new file mode 100644
index 0000000..58adb69
--- /dev/null
+++ b/GpCommon/GpString.h
@@ -0,0 +1,150 @@
+#pragma once
+
+#include "GpVector.h"
+
+#include
+#include
+
+template
+class GpString
+{
+public:
+ explicit GpString(IGpAllocator *alloc);
+ GpString(GpString &&other);
+
+ bool Set(const TChar *str);
+ bool Set(const TChar *str, size_t len);
+ bool Set(const GpString &other);
+
+ bool Append(const TChar *str);
+ bool Append(const TChar *str, size_t len);
+ bool Append(const GpString &other);
+
+ TChar *Buffer();
+ const TChar *Buffer() const ;
+
+
+private:
+ static const size_t kStaticSize = 32;
+
+ GpVector m_chars;
+ size_t m_length;
+};
+
+typedef GpString GpCString;
+typedef GpString GpWString;
+
+#include
+#include
+
+template
+GpString::GpString(IGpAllocator *alloc)
+ : m_chars(alloc)
+ , m_length(0)
+{
+ (void)m_chars.Resize(1);
+ m_chars[0] = static_cast(0);
+}
+
+template
+GpString::GpString(GpString &&other)
+ : m_chars(static_cast&&>(other.m_chars))
+ , m_length(other.m_length)
+{
+ other.m_length = 0;
+}
+
+
+template
+bool GpString::Set(const TChar *str)
+{
+ size_t len = 0;
+ while (str[len] != static_cast(0))
+ len++;
+
+ return this->Set(str, len);
+}
+
+template
+bool GpString::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(0);
+
+ m_length = len;
+
+ return true;
+}
+
+template
+bool GpString::Set(const GpString &other)
+{
+ if (&other == this)
+ return true;
+
+ return this->Set(other.Buffer(), other.m_length);
+}
+
+template
+bool GpString::Append(const TChar *str)
+{
+ size_t len = 0;
+ while (str[len] != static_cast(0))
+ len++;
+
+ return this->Append(str, len);
+}
+
+template
+bool GpString::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(0);
+
+ m_length += len;
+
+ return true;
+}
+
+template
+bool GpString::Append(const GpString &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(0);
+
+ m_length += other.m_length;
+
+ return true;
+}
+
+template
+TChar *GpString::Buffer()
+{
+ return m_chars.Buffer();
+}
+
+template
+const TChar *GpString::Buffer() const
+{
+ return m_chars.Buffer();
+}
diff --git a/GpCommon/GpVector.h b/GpCommon/GpVector.h
new file mode 100644
index 0000000..1472363
--- /dev/null
+++ b/GpCommon/GpVector.h
@@ -0,0 +1,230 @@
+#pragma once
+
+#include "CoreDefs.h"
+
+#include
+
+struct IGpAllocator;
+
+template
+class GpVectorStaticData
+{
+protected:
+ GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) uint8_t m_staticElementData[sizeof(T) * TStaticSize];
+
+ T *GetStaticElements();
+ const T *GetStaticElements() const;
+};
+
+template
+class GpVectorStaticData
+{
+protected:
+ T *GetStaticElements();
+ const T *GetStaticElements() const;
+};
+
+
+template
+class GpVector : public GpVectorStaticData
+{
+public:
+ explicit GpVector(IGpAllocator *alloc);
+ GpVector(GpVector &&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 &other) GP_DELETED;
+
+ static const size_t kStaticSize = TStaticSize;
+
+ T *m_elements;
+ size_t m_capacity;
+ size_t m_count;
+ IGpAllocator *m_alloc;
+};
+
+#include
+#include
+#include "IGpAllocator.h"
+
+template
+T *GpVectorStaticData::GetStaticElements()
+{
+ return reinterpret_cast(this->m_staticElementData);
+}
+
+template
+const T *GpVectorStaticData::GetStaticElements() const
+{
+ return reinterpret_cast(this->m_staticElementData);
+}
+
+template
+T *GpVectorStaticData::GetStaticElements()
+{
+ return nullptr;
+}
+
+template
+const T *GpVectorStaticData::GetStaticElements() const
+{
+ return nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GpVector
+template
+GpVector::GpVector(IGpAllocator *alloc)
+ : m_elements(this->GetStaticElements())
+ , m_capacity(TStaticSize)
+ , m_count(0)
+ , m_alloc(alloc)
+{
+}
+
+template
+GpVector::GpVector(GpVector &&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(other.m_elements));
+ }
+
+ other.m_count = 0;
+ other.m_capacity = 0;
+ other.m_elements = nullptr;
+}
+
+template
+GpVector::~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
+T &GpVector::operator[](size_t index)
+{
+ assert(index <= m_count);
+ return m_elements[index];
+}
+
+template
+const T &GpVector::operator[](size_t index) const
+{
+ assert(index <= m_count);
+ return m_elements[index];
+}
+
+
+template
+bool GpVector::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
+bool GpVector::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(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(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
+const size_t GpVector::Count() const
+{
+ return m_count;
+}
+
+template
+T *GpVector::Buffer()
+{
+ return m_elements;
+}
+
+template
+const T *GpVector::Buffer() const
+{
+ return m_elements;
+}