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