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; +}