Files
WickedEngine/WickedEngine/wiHelper.cpp
T
2019-01-26 19:43:43 +00:00

360 lines
8.7 KiB
C++

#include "wiHelper.h"
#include "wiRenderer.h"
#include "wiBackLog.h"
#include "wiWindowRegistration.h"
#include "Utility/stb_image_write.h"
#include <locale>
#include <direct.h>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <sstream>
using namespace std;
namespace wiHelper
{
DataBlob::DataBlob(const string& fileName) : DATA(nullptr), dataSize(0), dataPos(0)
{
ifstream file(fileName, ios::binary | ios::ate);
if (file.is_open())
{
dataSize = static_cast<size_t>(file.tellg());
file.seekg(0, file.beg);
DATA = new char[dataSize];
file.read(DATA, dataSize);
file.close();
dataPos = reinterpret_cast<size_t>(DATA);
}
}
DataBlob::~DataBlob()
{
SAFE_DELETE_ARRAY(DATA);
}
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(wiWindowRegistration::GetRegisteredWindow(), msg.c_str(), caption.c_str(), 0);
#else
wstring wmsg(msg.begin(), msg.end());
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 saveTextureToFile(wiGraphicsTypes::Texture2D& texture, const string& fileName)
{
using namespace wiGraphicsTypes;
GraphicsDevice* device = wiRenderer::GetDevice();
device->WaitForGPU();
TextureDesc desc = texture.GetDesc();
UINT data_count = desc.Width * desc.Height;
UINT data_stride = device->GetFormatStride(desc.Format);
UINT data_size = data_count * data_stride;
vector<uint8_t> data(data_size);
Texture2D* stagingTex = nullptr;
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->CreateTexture2D(&staging_desc, nullptr, &stagingTex);
assert(SUCCEEDED(hr));
bool download_success = device->DownloadResource(&texture, stagingTex, data.data(), GRAPHICSTHREAD_IMMEDIATE);
assert(download_success);
SAFE_DELETE(stagingTex);
return saveTextureToFile(data, desc, fileName);
}
bool saveTextureToFile(const std::vector<uint8_t>& textureData, const wiGraphicsTypes::TextureDesc& desc, const std::string& fileName)
{
using namespace wiGraphicsTypes;
UINT 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 (UINT 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)
{
LPSTR fileName = new CHAR[1024];
GetModuleFileNameA(NULL, fileName, 1024);
__appDir = GetDirectoryFromPath(fileName);
delete[] fileName;
__initComplete = true;
}
return __appDir;
}
string GetOriginalWorkingDirectory()
{
static const string __originalWorkingDir = GetWorkingDirectory();
return __originalWorkingDir;
}
string GetWorkingDirectory()
{
return string(_getcwd(NULL, 0)) + "/";
}
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 = wstring(directory.begin(), directory.end());
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;
out.push_back(string(full_file_name.begin(), full_file_name.end()));
} 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 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();
}
}
}