Files
WickedEngine/WickedEngine/wiHelper.cpp
T
2020-04-24 23:48:54 +01:00

475 lines
11 KiB
C++

#include "wiHelper.h"
#include "wiPlatform.h"
#include "wiRenderer.h"
#include "wiBackLog.h"
#include "Utility/stb_image_write.h"
#include <locale>
#include <direct.h>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <codecvt> // string conversion
#include <Commdlg.h> // openfile
#include <WinBase.h>
using namespace std;
namespace wiHelper
{
string toUpper(const std::string& s)
{
std::string result;
std::locale loc;
for (unsigned int i = 0; i < s.length(); ++i)
{
result += std::toupper(s.at(i), loc);
}
return result;
}
bool readByteData(const std::string& fileName, std::vector<uint8_t>& data)
{
ifstream file(fileName, ios::binary | ios::ate);
if (file.is_open())
{
size_t dataSize = (size_t)file.tellg();
file.seekg(0, file.beg);
data.resize(dataSize);
file.read((char*)data.data(), dataSize);
file.close();
return true;
}
stringstream ss("");
ss << "File not found: " << fileName;
messageBox(ss.str());
return false;
}
void messageBox(const std::string& msg, const std::string& caption)
{
#ifndef WINSTORE_SUPPORT
MessageBoxA(wiPlatform::GetWindow(), msg.c_str(), caption.c_str(), 0);
#else
wstring wmsg;
StringConvert(msg, wmsg);
wstring wcaption(caption.begin(), caption.end());
Windows::UI::Popups::MessageDialog(ref new Platform::String(wmsg.c_str()), ref new Platform::String(wcaption.c_str())).ShowAsync();
#endif
}
void screenshot(const std::string& name)
{
CreateDirectoryA("screenshots", 0);
stringstream ss("");
if (name.length() <= 0)
ss << GetOriginalWorkingDirectory() << "screenshots/sc_" << getCurrentDateTimeAsString() << ".jpg";
else
ss << name;
bool result = saveTextureToFile(wiRenderer::GetDevice()->GetBackBuffer(), ss.str());
assert(result);
}
bool saveTextureToMemory(const wiGraphics::Texture& texture, std::vector<uint8_t>& data)
{
using namespace wiGraphics;
GraphicsDevice* device = wiRenderer::GetDevice();
device->WaitForGPU();
TextureDesc desc = texture.GetDesc();
uint32_t data_count = desc.Width * desc.Height;
uint32_t data_stride = device->GetFormatStride(desc.Format);
uint32_t data_size = data_count * data_stride;
data.resize(data_size);
Texture stagingTex;
TextureDesc staging_desc = desc;
staging_desc.Usage = USAGE_STAGING;
staging_desc.CPUAccessFlags = CPU_ACCESS_READ;
staging_desc.BindFlags = 0;
staging_desc.MiscFlags = 0;
HRESULT hr = device->CreateTexture(&staging_desc, nullptr, &stagingTex);
assert(SUCCEEDED(hr));
bool download_success = device->DownloadResource(&texture, &stagingTex, data.data());
assert(download_success);
return download_success;
}
bool saveTextureToFile(const wiGraphics::Texture& texture, const string& fileName)
{
using namespace wiGraphics;
TextureDesc desc = texture.GetDesc();
std::vector<uint8_t> data;
if (saveTextureToMemory(texture, data))
{
return saveTextureToFile(data, desc, fileName);
}
return false;
}
bool saveTextureToFile(const std::vector<uint8_t>& textureData, const wiGraphics::TextureDesc& desc, const std::string& fileName)
{
using namespace wiGraphics;
uint32_t data_count = desc.Width * desc.Height;
if (desc.Format == FORMAT_R10G10B10A2_UNORM)
{
// So this should be converted first to rgba8 before saving to common format...
uint32_t* data32 = (uint32_t*)textureData.data();
for (uint32_t i = 0; i < data_count; ++i)
{
uint32_t pixel = data32[i];
float r = ((pixel >> 0) & 1023) / 1023.0f;
float g = ((pixel >> 10) & 1023) / 1023.0f;
float b = ((pixel >> 20) & 1023) / 1023.0f;
float a = ((pixel >> 30) & 3) / 3.0f;
uint32_t rgba8 = 0;
rgba8 |= (uint32_t)(r * 255.0f) << 0;
rgba8 |= (uint32_t)(g * 255.0f) << 8;
rgba8 |= (uint32_t)(b * 255.0f) << 16;
rgba8 |= (uint32_t)(a * 255.0f) << 24;
data32[i] = rgba8;
}
}
else
{
assert(desc.Format == FORMAT_R8G8B8A8_UNORM); // If you need to save other backbuffer format, convert the data here yourself...
}
int write_result = 0;
string extension = wiHelper::toUpper(wiHelper::GetExtensionFromFileName(fileName));
if (!extension.compare("JPG"))
{
write_result = stbi_write_jpg(fileName.c_str(), (int)desc.Width, (int)desc.Height, 4, textureData.data(), 100);
}
else if (!extension.compare("PNG"))
{
write_result = stbi_write_png(fileName.c_str(), (int)desc.Width, (int)desc.Height, 4, textureData.data(), 0);
}
else if (!extension.compare("TGA"))
{
write_result = stbi_write_tga(fileName.c_str(), (int)desc.Width, (int)desc.Height, 4, textureData.data());
}
else if (!extension.compare("BMP"))
{
write_result = stbi_write_bmp(fileName.c_str(), (int)desc.Width, (int)desc.Height, 4, textureData.data());
}
else
{
assert(0 && "Unsupported extension");
}
return write_result != 0;
}
string getCurrentDateTimeAsString()
{
time_t t = std::time(nullptr);
struct tm time_info;
localtime_s(&time_info, &t);
stringstream ss("");
ss << std::put_time(&time_info, "%d-%m-%Y %H-%M-%S");
return ss.str();
}
string GetApplicationDirectory()
{
static string appDir;
static bool initComplete = false;
if (!initComplete)
{
CHAR fileName[1024] = {};
GetModuleFileNameA(NULL, fileName, arraysize(fileName));
appDir = GetDirectoryFromPath(fileName);
initComplete = true;
}
return appDir;
}
string GetOriginalWorkingDirectory()
{
static const string __originalWorkingDir = GetWorkingDirectory();
return __originalWorkingDir;
}
string GetWorkingDirectory()
{
char* cwd = _getcwd(NULL, 0);
if (cwd != nullptr)
{
return string(cwd) + "/";
}
return "/";
}
bool SetWorkingDirectory(const std::string& path)
{
return _chdir(path.c_str()) == 0;
}
void GetFilesInDirectory(std::vector<string>& out, const std::string& directory)
{
#ifndef WINSTORE_SUPPORT
// WINDOWS
wstring wdirectory;
StringConvert(directory, wdirectory);
HANDLE dir;
WIN32_FIND_DATA file_data;
if ((dir = FindFirstFile((wdirectory + L"/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
return; /* No files found */
do {
const wstring file_name = file_data.cFileName;
const wstring full_file_name = wdirectory + L"/" + file_name;
const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
//if (file_name[0] == '.')
// continue;
//if (is_directory)
// continue;
string fname;
StringConvert(full_file_name, fname);
out.push_back(fname);
} while (FindNextFile(dir, &file_data));
FindClose(dir);
#endif
// UNIX
//DIR *dir;
//class dirent *ent;
//class stat st;
//dir = opendir(directory);
//while ((ent = readdir(dir)) != NULL) {
// const string file_name = ent->d_name;
// const string full_file_name = directory + "/" + file_name;
// if (file_name[0] == '.')
// continue;
// if (stat(full_file_name.c_str(), &st) == -1)
// continue;
// const bool is_directory = (st.st_mode & S_IFDIR) != 0;
// if (is_directory)
// continue;
// out.push_back(full_file_name);
//}
//closedir(dir);
}
void SplitPath(const std::string& fullPath, string& dir, string& fileName)
{
size_t found;
found = fullPath.find_last_of("/\\");
dir = fullPath.substr(0, found + 1);
fileName = fullPath.substr(found + 1);
}
string GetFileNameFromPath(const std::string& fullPath)
{
if (fullPath.empty())
{
return fullPath;
}
string ret, empty;
SplitPath(fullPath, empty, ret);
return ret;
}
string GetDirectoryFromPath(const std::string& fullPath)
{
if (fullPath.empty())
{
return fullPath;
}
string ret, empty;
SplitPath(fullPath, ret, empty);
return ret;
}
string GetExtensionFromFileName(const string& filename)
{
size_t idx = filename.rfind('.');
if (idx != std::string::npos)
{
std::string extension = filename.substr(idx + 1);
return extension;
}
// No extension found
return "";
}
void RemoveExtensionFromFileName(std::string& filename)
{
string extension = GetExtensionFromFileName(filename);
if (!extension.empty())
{
filename = filename.substr(0, filename.length() - extension.length() - 1);
}
}
bool FileExists(const std::string& fileName)
{
ifstream f(fileName);
bool exists = f.is_open();
f.close();
return exists;
}
void FileDialog(const FileDialogParams& params, FileDialogResult& result)
{
#ifdef _WIN32
#ifndef WINSTORE_SUPPORT
char szFile[256];
OPENFILENAMEA ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = nullptr;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.nFilterIndex = 1;
// Slightly convoluted way to create the filter.
// First string is description, ended by '\0'
// Second string is extensions, each separated by ';' and at the end of all, a '\0'
// Then the whole container string is closed with an other '\0'
// For example: "model files\0*.model;*.obj;\0" <-- this string literal has "model files" as description and two accepted extensions "model" and "obj"
std::vector<char> filter;
filter.reserve(256);
{
for (auto& x : params.description)
{
filter.push_back(x);
}
filter.push_back(0);
for (auto& x : params.extensions)
{
filter.push_back('*');
filter.push_back('.');
for (auto& y : x)
{
filter.push_back(y);
}
filter.push_back(';');
}
filter.push_back(0);
filter.push_back(0);
}
ofn.lpstrFilter = filter.data();
switch (params.type)
{
case FileDialogParams::OPEN:
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
result.ok = GetOpenFileNameA(&ofn) == TRUE;
break;
case FileDialogParams::SAVE:
ofn.Flags = OFN_OVERWRITEPROMPT;
result.ok = GetSaveFileNameA(&ofn) == TRUE;
break;
}
if (result.ok)
{
result.filenames.push_back(ofn.lpstrFile);
}
#endif // WINSTORE_SUPPORT
#endif // _WIN32
}
void StringConvert(const std::string from, std::wstring& to)
{
int num = MultiByteToWideChar(CP_UTF8, 0, from.c_str(), -1, NULL, 0);
if (num > 0)
{
to.resize(size_t(num) - 1);
MultiByteToWideChar(CP_UTF8, 0, from.c_str(), -1, &to[0], num);
}
}
void StringConvert(const std::wstring from, std::string& to)
{
int num = WideCharToMultiByte(CP_UTF8, 0, from.c_str(), -1, NULL, 0, NULL, NULL);
if (num > 0)
{
to.resize(size_t(num) - 1);
WideCharToMultiByte(CP_UTF8, 0, from.c_str(), -1, &to[0], num, NULL, NULL);
}
}
int StringConvert(const char* from, wchar_t* to)
{
int num = MultiByteToWideChar(CP_UTF8, 0, from, -1, NULL, 0);
if (num > 0)
{
MultiByteToWideChar(CP_UTF8, 0, from, -1, &to[0], num);
}
return num;
}
int StringConvert(const wchar_t* from, char* to)
{
int num = WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL);
if (num > 0)
{
WideCharToMultiByte(CP_UTF8, 0, from, -1, &to[0], num, NULL, NULL);
}
return num;
}
void Sleep(float milliseconds)
{
::Sleep((DWORD)milliseconds);
}
void Spin(float milliseconds)
{
milliseconds /= 1000.0f;
chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
double ms = 0;
while (ms < milliseconds)
{
chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now();
chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
ms = time_span.count();
}
}
}