mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
272 lines
6.8 KiB
C++
272 lines
6.8 KiB
C++
#include "framework.h"
|
|
|
|
#include <codecvt>
|
|
#include <filesystem>
|
|
|
|
#include "Renderer/Renderer.h"
|
|
#include "Renderer/RendererEnums.h"
|
|
#include "Specific/trutils.h"
|
|
|
|
using TEN::Renderer::g_Renderer;
|
|
|
|
namespace TEN::Utils
|
|
{
|
|
std::string ConstructAssetDirectory(std::string customDirectory)
|
|
{
|
|
static const int searchDepth = 2;
|
|
static const std::string upDir = "../";
|
|
static const std::string testPath = "Scripts/Gameflow.lua";
|
|
|
|
if (!customDirectory.empty())
|
|
{
|
|
// Replace all backslashes with forward slashes.
|
|
std::replace(customDirectory.begin(), customDirectory.end(), '\\', '/');
|
|
|
|
// Add trailing slash if missing.
|
|
if (customDirectory.back() != '/')
|
|
customDirectory += '/';
|
|
}
|
|
|
|
// Wrap directory depth searching into try-catch block to avoid crashes if we get too
|
|
// shallow directory level (e.g. if user have placed executable in a disk root folder).
|
|
|
|
try
|
|
{
|
|
// First, search custom directory, if exists, only then try own (empty) subdirectory.
|
|
|
|
for (int useCustomSubdirectory = 1; useCustomSubdirectory >= 0; useCustomSubdirectory--)
|
|
{
|
|
// Quickly exit if no custom directory specified.
|
|
|
|
if (useCustomSubdirectory && customDirectory.empty())
|
|
continue;
|
|
|
|
for (int depth = 0; depth < searchDepth + 1; depth++)
|
|
{
|
|
auto result = useCustomSubdirectory ? customDirectory : std::string{};
|
|
bool isAbsolute = useCustomSubdirectory && std::filesystem::path(result).is_absolute();
|
|
|
|
if (isAbsolute)
|
|
{
|
|
// Custom directory may be specified as absolute. In such case, it makes no sense
|
|
// to search for assets on extra depth levels, since user never would expect that.
|
|
|
|
if (depth > 0)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Add upward directory levels, according to current depth.
|
|
|
|
for (int level = 0; level < depth; level++)
|
|
result = upDir + result;
|
|
}
|
|
|
|
// Look if provided test path / file exists in current folder. If it is,
|
|
// it means this is a valid asset folder.
|
|
|
|
auto testDir = result + (useCustomSubdirectory ? "/" : "") + testPath;
|
|
if (std::filesystem::is_regular_file(testDir))
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
catch (std::exception ex)
|
|
{
|
|
return std::string{}; // Use exe path if any error is encountered.
|
|
}
|
|
|
|
return std::string{}; // Use exe path if no any assets were found.
|
|
}
|
|
|
|
std::string ToUpper(std::string string)
|
|
{
|
|
std::transform(string.begin(), string.end(), string.begin(), [](unsigned char c) { return std::toupper(c); });
|
|
return string;
|
|
}
|
|
|
|
std::string ToLower(std::string string)
|
|
{
|
|
std::transform(string.begin(), string.end(), string.begin(), [](unsigned char c) { return std::tolower(c); });
|
|
return string;
|
|
}
|
|
|
|
std::string ToString(const std::wstring& wString)
|
|
{
|
|
return ToString(wString.c_str());
|
|
}
|
|
|
|
std::string ToString(const wchar_t* wString)
|
|
{
|
|
auto converter = std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>();
|
|
return converter.to_bytes(std::wstring(wString));
|
|
}
|
|
|
|
std::wstring ToWString(const std::string& string)
|
|
{
|
|
auto cString = string.c_str();
|
|
int size = MultiByteToWideChar(CP_UTF8, 0, cString, (int)string.size(), nullptr, 0);
|
|
auto wString = std::wstring(size, 0);
|
|
MultiByteToWideChar(CP_UTF8, 0, cString, (int)strlen(cString), &wString[0], size);
|
|
return wString;
|
|
}
|
|
|
|
std::wstring ToWString(const char* cString)
|
|
{
|
|
wchar_t buffer[UCHAR_MAX];
|
|
std::mbstowcs(buffer, cString, UCHAR_MAX);
|
|
return std::wstring(buffer);
|
|
}
|
|
|
|
std::string ReplaceNewLineSymbols(const std::string& string)
|
|
{
|
|
auto result = string;
|
|
std::string::size_type index = 0;
|
|
|
|
while ((index = result.find("\\n", index)) != std::string::npos)
|
|
{
|
|
result.replace(index, 2, "\n");
|
|
++index;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::wstring> SplitString(const std::wstring& string)
|
|
{
|
|
auto strings = std::vector<std::wstring>{};
|
|
|
|
// Exit early if string is single line.
|
|
if (string.find(L'\n') == std::wstring::npos)
|
|
{
|
|
strings.push_back(string);
|
|
return strings;
|
|
}
|
|
|
|
std::wstring::size_type pos = 0;
|
|
std::wstring::size_type prev = 0;
|
|
while ((pos = string.find(L'\n', prev)) != std::string::npos)
|
|
{
|
|
strings.push_back(string.substr(prev, pos - prev));
|
|
prev = pos + 1;
|
|
}
|
|
|
|
strings.push_back(string.substr(prev));
|
|
return strings;
|
|
}
|
|
|
|
int GetHash(const std::string& string)
|
|
{
|
|
if (string.empty())
|
|
return 0;
|
|
|
|
uint32_t hash = 2166136261u;
|
|
for (char c : string)
|
|
{
|
|
hash ^= static_cast<uint8_t>(c);
|
|
hash *= 16777619u;
|
|
}
|
|
|
|
return static_cast<int>(hash);
|
|
}
|
|
|
|
Vector2 GetAspectCorrect2DPosition(const Vector2& pos)
|
|
{
|
|
constexpr auto DISPLAY_SPACE_ASPECT = DISPLAY_SPACE_RES.x / DISPLAY_SPACE_RES.y;
|
|
|
|
auto screenRes = g_Renderer.GetScreenResolution().ToVector2();
|
|
float screenResAspect = screenRes.x / screenRes.y;
|
|
float aspectDelta = screenResAspect - DISPLAY_SPACE_ASPECT;
|
|
|
|
auto correctedPos = pos;
|
|
if (aspectDelta > EPSILON)
|
|
{
|
|
correctedPos.x *= 1.0f - (aspectDelta / 2);
|
|
}
|
|
else if (aspectDelta < -EPSILON)
|
|
{
|
|
correctedPos.y *= 1.0f - (aspectDelta / 2);
|
|
}
|
|
|
|
return correctedPos;
|
|
}
|
|
|
|
Vector2 Convert2DPositionToNDC(const Vector2& pos)
|
|
{
|
|
return Vector2(
|
|
((pos.x * 2) / DISPLAY_SPACE_RES.x) - 1.0f,
|
|
1.0f - ((pos.y * 2) / DISPLAY_SPACE_RES.y));
|
|
}
|
|
|
|
Vector2 ConvertNDCTo2DPosition(const Vector2& ndc)
|
|
{
|
|
return Vector2(
|
|
((ndc.x + 1.0f) * DISPLAY_SPACE_RES.x) / 2,
|
|
((1.0f - ndc.y) * DISPLAY_SPACE_RES.y) / 2);
|
|
}
|
|
|
|
std::vector<unsigned short> GetProductOrFileVersion(bool productVersion)
|
|
{
|
|
wchar_t fileName[UCHAR_MAX] = {};
|
|
|
|
if (!GetModuleFileNameW(nullptr, fileName, UCHAR_MAX))
|
|
{
|
|
TENLog("Can't get current assembly filename", LogLevel::Error);
|
|
return {};
|
|
}
|
|
|
|
DWORD dummy;
|
|
DWORD size = GetFileVersionInfoSizeW(fileName, &dummy);
|
|
|
|
if (size == 0)
|
|
{
|
|
TENLog("GetFileVersionInfoSizeW failed", LogLevel::Error);
|
|
return {};
|
|
}
|
|
|
|
std::unique_ptr<unsigned char[]> buffer(new unsigned char[size]);
|
|
|
|
// Load version info.
|
|
if (!GetFileVersionInfoW(fileName, 0, size, buffer.get()))
|
|
{
|
|
TENLog("GetFileVersionInfoW failed", LogLevel::Error);
|
|
return {};
|
|
}
|
|
|
|
VS_FIXEDFILEINFO* info;
|
|
unsigned int infoSize;
|
|
|
|
if (!VerQueryValueW(buffer.get(), L"\\", (void**)&info, &infoSize))
|
|
{
|
|
TENLog("VerQueryValueW failed", LogLevel::Error);
|
|
return {};
|
|
}
|
|
|
|
if (infoSize != sizeof(VS_FIXEDFILEINFO))
|
|
{
|
|
TENLog("VerQueryValueW returned wrong size for VS_FIXEDFILEINFO", LogLevel::Error);
|
|
return {};
|
|
}
|
|
|
|
if (productVersion)
|
|
{
|
|
return
|
|
{
|
|
HIWORD(info->dwProductVersionMS),
|
|
LOWORD(info->dwProductVersionMS),
|
|
HIWORD(info->dwProductVersionLS),
|
|
LOWORD(info->dwProductVersionLS)
|
|
};
|
|
}
|
|
else
|
|
{
|
|
return
|
|
{
|
|
HIWORD(info->dwFileVersionMS),
|
|
LOWORD(info->dwFileVersionMS),
|
|
HIWORD(info->dwFileVersionLS),
|
|
LOWORD(info->dwFileVersionLS)
|
|
};
|
|
}
|
|
}
|
|
}
|