Refactor + render animation tweaks + updated frame properties + bug fixes
This commit is contained in:
41
src/util/file_.cpp
Normal file
41
src/util/file_.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "file_.h"
|
||||
|
||||
namespace anm2ed::util
|
||||
{
|
||||
File::File(const std::filesystem::path& path, const char* mode) { open(path, mode); }
|
||||
|
||||
File::~File() { close(); }
|
||||
|
||||
bool File::open(const std::filesystem::path& path, const char* mode)
|
||||
{
|
||||
close();
|
||||
|
||||
#ifdef _WIN32
|
||||
std::wstring wideMode{};
|
||||
if (mode)
|
||||
wideMode.assign(mode, mode + std::strlen(mode));
|
||||
else
|
||||
wideMode = L"rb";
|
||||
handle = _wfopen(path.native().c_str(), wideMode.c_str());
|
||||
#else
|
||||
handle = std::fopen(path.string().c_str(), mode);
|
||||
#endif
|
||||
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
int File::close()
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
auto result = std::fclose(handle);
|
||||
handle = nullptr;
|
||||
return result;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* File::get() const { return handle; }
|
||||
|
||||
File::operator bool() const { return handle != nullptr; }
|
||||
}
|
||||
22
src/util/file_.h
Normal file
22
src/util/file_.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace anm2ed::util
|
||||
{
|
||||
class File
|
||||
{
|
||||
public:
|
||||
File() = default;
|
||||
File(const std::filesystem::path&, const char* mode);
|
||||
~File();
|
||||
|
||||
bool open(const std::filesystem::path&, const char* mode);
|
||||
int close();
|
||||
FILE* get() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
FILE* handle{};
|
||||
};
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
#include "filesystem_.h"
|
||||
|
||||
#include <SDL3/SDL_filesystem.h>
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cwctype>
|
||||
#include <filesystem>
|
||||
#include <type_traits>
|
||||
|
||||
namespace anm2ed::util::filesystem
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <typename CharT> CharT to_lower_char(CharT character)
|
||||
{
|
||||
if constexpr (std::is_same_v<CharT, wchar_t>)
|
||||
return static_cast<CharT>(std::towlower(static_cast<wint_t>(character)));
|
||||
else
|
||||
return static_cast<CharT>(std::tolower(static_cast<unsigned char>(character)));
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path path_preferences_get()
|
||||
{
|
||||
auto sdlPath = SDL_GetPrefPath(nullptr, "anm2ed");
|
||||
if (!sdlPath) return {};
|
||||
auto filePath = path_from_utf8(sdlPath);
|
||||
SDL_free(sdlPath);
|
||||
return filePath;
|
||||
}
|
||||
|
||||
std::filesystem::path path_to_lower(const std::filesystem::path& path)
|
||||
{
|
||||
auto native = path.native();
|
||||
for (auto& character : native)
|
||||
character = to_lower_char(character);
|
||||
return std::filesystem::path(native);
|
||||
}
|
||||
|
||||
std::filesystem::path path_backslash_replace(const std::filesystem::path& path)
|
||||
{
|
||||
auto native = path.native();
|
||||
constexpr auto backslash = static_cast<std::filesystem::path::value_type>('\\');
|
||||
constexpr auto slash = static_cast<std::filesystem::path::value_type>('/');
|
||||
for (auto& character : native)
|
||||
if (character == backslash) character = slash;
|
||||
return std::filesystem::path(native);
|
||||
}
|
||||
|
||||
std::string path_to_utf8(const std::filesystem::path& path)
|
||||
{
|
||||
auto u8 = path.u8string();
|
||||
return std::string(u8.begin(), u8.end());
|
||||
}
|
||||
|
||||
std::filesystem::path path_from_utf8(const std::string& utf8)
|
||||
{
|
||||
return std::filesystem::path(std::u8string(utf8.begin(), utf8.end()));
|
||||
}
|
||||
|
||||
FILE* open(const std::filesystem::path& path, const char* mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::wstring wideMode{};
|
||||
if (mode)
|
||||
wideMode.assign(mode, mode + std::strlen(mode));
|
||||
else
|
||||
wideMode = L"rb";
|
||||
return _wfopen(path.native().c_str(), wideMode.c_str());
|
||||
#else
|
||||
return std::fopen(path.string().c_str(), mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool path_is_exist(const std::filesystem::path& path)
|
||||
{
|
||||
std::error_code errorCode;
|
||||
return std::filesystem::exists(path, errorCode) && ((void)std::filesystem::status(path, errorCode), !errorCode);
|
||||
}
|
||||
|
||||
bool path_is_extension(const std::filesystem::path& path, const std::string& extension)
|
||||
{
|
||||
auto extensionUtf8 = path_to_utf8(std::filesystem::path(path).extension());
|
||||
std::transform(extensionUtf8.begin(), extensionUtf8.end(), extensionUtf8.begin(), ::tolower);
|
||||
return extensionUtf8 == ("." + extension);
|
||||
}
|
||||
|
||||
std::filesystem::path path_lower_case_backslash_handle(const std::filesystem::path& path)
|
||||
{
|
||||
auto newPath = path;
|
||||
if (path_is_exist(newPath)) return newPath;
|
||||
|
||||
newPath = path_backslash_replace(newPath);
|
||||
if (path_is_exist(newPath)) return newPath;
|
||||
|
||||
newPath = path_to_lower(newPath);
|
||||
return newPath;
|
||||
}
|
||||
|
||||
WorkingDirectory::WorkingDirectory(const std::filesystem::path& path, bool isFile)
|
||||
{
|
||||
previous = std::filesystem::current_path();
|
||||
if (isFile)
|
||||
{
|
||||
std::filesystem::path filePath = path;
|
||||
std::filesystem::path parentPath = filePath.parent_path();
|
||||
std::filesystem::current_path(parentPath);
|
||||
}
|
||||
else
|
||||
std::filesystem::current_path(path);
|
||||
}
|
||||
|
||||
WorkingDirectory::~WorkingDirectory() { std::filesystem::current_path(previous); }
|
||||
|
||||
File::File(const std::filesystem::path& path, const char* mode) { open(path, mode); }
|
||||
|
||||
File::~File() { close(); }
|
||||
|
||||
bool File::open(const std::filesystem::path& path, const char* mode)
|
||||
{
|
||||
close();
|
||||
handle = filesystem::open(path, mode);
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
void File::close()
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
std::fclose(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* File::get() const { return handle; }
|
||||
|
||||
File::operator bool() const { return handle != nullptr; }
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace anm2ed::util::filesystem
|
||||
{
|
||||
std::filesystem::path path_preferences_get();
|
||||
std::filesystem::path path_to_lower(const std::filesystem::path&);
|
||||
std::filesystem::path path_backslash_replace(const std::filesystem::path&);
|
||||
std::string path_to_utf8(const std::filesystem::path&);
|
||||
std::filesystem::path path_from_utf8(const std::string&);
|
||||
|
||||
bool path_is_exist(const std::filesystem::path&);
|
||||
bool path_is_extension(const std::filesystem::path&, const std::string&);
|
||||
|
||||
std::filesystem::path path_lower_case_backslash_handle(const std::filesystem::path&);
|
||||
|
||||
FILE* open(const std::filesystem::path&, const char*);
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
File() = default;
|
||||
File(const std::filesystem::path&, const char* mode);
|
||||
~File();
|
||||
|
||||
bool open(const std::filesystem::path&, const char* mode);
|
||||
void close();
|
||||
FILE* get() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
FILE* handle{};
|
||||
};
|
||||
|
||||
class WorkingDirectory
|
||||
{
|
||||
public:
|
||||
std::filesystem::path previous;
|
||||
|
||||
WorkingDirectory(const std::filesystem::path&, bool = false);
|
||||
~WorkingDirectory();
|
||||
};
|
||||
|
||||
}
|
||||
120
src/util/path_.cpp
Normal file
120
src/util/path_.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "path_.h"
|
||||
|
||||
#include <SDL3/SDL_filesystem.h>
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <cctype>
|
||||
#include <cwctype>
|
||||
#include <filesystem>
|
||||
#include <type_traits>
|
||||
|
||||
namespace anm2ed::util::path
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <typename CharT> CharT to_lower_char(CharT character)
|
||||
{
|
||||
if constexpr (std::is_same_v<CharT, wchar_t>)
|
||||
return static_cast<CharT>(std::towlower(static_cast<wint_t>(character)));
|
||||
else
|
||||
return static_cast<CharT>(std::tolower(static_cast<unsigned char>(character)));
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path to_lower(const std::filesystem::path& path)
|
||||
{
|
||||
auto native = path.native();
|
||||
for (auto& character : native)
|
||||
character = to_lower_char(character);
|
||||
return std::filesystem::path(native);
|
||||
}
|
||||
|
||||
std::filesystem::path backslash_replace(const std::filesystem::path& path)
|
||||
{
|
||||
auto native = path.native();
|
||||
constexpr auto backslash = static_cast<std::filesystem::path::value_type>('\\');
|
||||
constexpr auto slash = static_cast<std::filesystem::path::value_type>('/');
|
||||
for (auto& character : native)
|
||||
if (character == backslash) character = slash;
|
||||
return std::filesystem::path(native);
|
||||
}
|
||||
|
||||
std::string to_utf8(const std::filesystem::path& path)
|
||||
{
|
||||
auto u8 = path.u8string();
|
||||
return std::string(u8.begin(), u8.end());
|
||||
}
|
||||
|
||||
std::filesystem::path from_utf8(const std::string& utf8)
|
||||
{
|
||||
return std::filesystem::path(std::u8string(utf8.begin(), utf8.end()));
|
||||
}
|
||||
|
||||
bool is_exist(const std::filesystem::path& path)
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
std::error_code errorCode;
|
||||
return std::filesystem::exists(path, errorCode) && ((void)std::filesystem::status(path, errorCode), !errorCode);
|
||||
}
|
||||
|
||||
bool is_extension(const std::filesystem::path& path, const std::string& extension)
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
auto extensionUtf8 = to_utf8(std::filesystem::path(path).extension());
|
||||
std::transform(extensionUtf8.begin(), extensionUtf8.end(), extensionUtf8.begin(), ::tolower);
|
||||
return extensionUtf8 == ("." + extension);
|
||||
}
|
||||
|
||||
bool is_executable(const std::filesystem::path& path)
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
|
||||
std::error_code ec;
|
||||
auto status = std::filesystem::status(path, ec);
|
||||
if (ec) return false;
|
||||
if (!std::filesystem::exists(status)) return false;
|
||||
if (!std::filesystem::is_regular_file(status)) return false;
|
||||
|
||||
#ifdef WIN32
|
||||
auto extension = to_lower(path.extension());
|
||||
if (extension != ".exe" && extension != ".bat" && extension != ".cmd") return false;
|
||||
#else
|
||||
auto permissions = status.permissions();
|
||||
auto executableMask =
|
||||
std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec;
|
||||
if ((permissions & executableMask) == std::filesystem::perms::none) return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ensure_directory(const std::filesystem::path& path)
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
|
||||
std::error_code ec;
|
||||
if (std::filesystem::create_directories(path, ec)) return true;
|
||||
|
||||
return is_exist(path.parent_path());
|
||||
}
|
||||
|
||||
std::filesystem::path make_relative(const std::filesystem::path& path)
|
||||
{
|
||||
if (path.empty()) return path;
|
||||
std::error_code ec{};
|
||||
auto relative = std::filesystem::relative(path, ec);
|
||||
if (!ec) return relative;
|
||||
return path;
|
||||
}
|
||||
|
||||
std::filesystem::path lower_case_backslash_handle(const std::filesystem::path& path)
|
||||
{
|
||||
auto newPath = path;
|
||||
if (is_exist(newPath)) return newPath;
|
||||
|
||||
newPath = backslash_replace(newPath);
|
||||
if (is_exist(newPath)) return newPath;
|
||||
|
||||
newPath = to_lower(newPath);
|
||||
return newPath;
|
||||
}
|
||||
}
|
||||
21
src/util/path_.h
Normal file
21
src/util/path_.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace anm2ed::util::path
|
||||
{
|
||||
std::filesystem::path to_lower(const std::filesystem::path&);
|
||||
std::filesystem::path backslash_replace(const std::filesystem::path&);
|
||||
std::string to_utf8(const std::filesystem::path&);
|
||||
std::filesystem::path from_utf8(const std::string&);
|
||||
std::filesystem::path make_relative(const std::filesystem::path&);
|
||||
|
||||
bool is_exist(const std::filesystem::path&);
|
||||
bool is_executable(const std::filesystem::path&);
|
||||
bool is_extension(const std::filesystem::path&, const std::string&);
|
||||
|
||||
bool ensure_directory(const std::filesystem::path&);
|
||||
|
||||
std::filesystem::path lower_case_backslash_handle(const std::filesystem::path&);
|
||||
}
|
||||
55
src/util/process_.cpp
Normal file
55
src/util/process_.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "process_.h"
|
||||
|
||||
namespace anm2ed::util
|
||||
{
|
||||
Process::Process(const char* command, const char* mode) { open(command, mode); }
|
||||
|
||||
Process::~Process() { close(); }
|
||||
|
||||
bool Process::open(const char* command, const char* mode)
|
||||
{
|
||||
close();
|
||||
|
||||
#ifdef WIN32
|
||||
pipe = _popen(command, mode);
|
||||
#else
|
||||
pipe = popen(command, mode);
|
||||
#endif
|
||||
return pipe != nullptr;
|
||||
}
|
||||
|
||||
int Process::close()
|
||||
{
|
||||
if (pipe)
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto result = _pclose(pipe);
|
||||
#else
|
||||
auto result = pclose(pipe);
|
||||
#endif
|
||||
pipe = nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string Process::output_get_and_close()
|
||||
{
|
||||
std::string output{};
|
||||
if (!pipe) return {};
|
||||
|
||||
char buffer[256];
|
||||
while (fgets(buffer, sizeof(buffer), pipe))
|
||||
output += buffer;
|
||||
|
||||
close();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
FILE* Process::get() const { return pipe; }
|
||||
|
||||
Process::operator bool() const { return pipe != nullptr; }
|
||||
}
|
||||
24
src/util/process_.h
Normal file
24
src/util/process_.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace anm2ed::util
|
||||
{
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
Process() = default;
|
||||
Process(const char*, const char*);
|
||||
~Process();
|
||||
|
||||
bool open(const char*, const char*);
|
||||
int close();
|
||||
FILE* get() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
std::string output_get_and_close();
|
||||
|
||||
private:
|
||||
FILE* pipe{};
|
||||
};
|
||||
}
|
||||
17
src/util/sdl.cpp
Normal file
17
src/util/sdl.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "sdl.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "path_.h"
|
||||
|
||||
namespace anm2ed::util::sdl
|
||||
{
|
||||
std::filesystem::path preferences_directory_get()
|
||||
{
|
||||
auto sdlPath = SDL_GetPrefPath(nullptr, "anm2ed");
|
||||
if (!sdlPath) return {};
|
||||
auto filePath = path::from_utf8(sdlPath);
|
||||
SDL_free(sdlPath);
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
8
src/util/sdl.h
Normal file
8
src/util/sdl.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace anm2ed::util::sdl
|
||||
{
|
||||
std::filesystem::path preferences_directory_get();
|
||||
}
|
||||
19
src/util/working_directory.cpp
Normal file
19
src/util/working_directory.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "working_directory.h"
|
||||
|
||||
namespace anm2ed::util
|
||||
{
|
||||
WorkingDirectory::WorkingDirectory(const std::filesystem::path& path, Type type)
|
||||
{
|
||||
previous = std::filesystem::current_path();
|
||||
if (type == FILE)
|
||||
{
|
||||
std::filesystem::path filePath = path;
|
||||
std::filesystem::path parentPath = filePath.parent_path();
|
||||
std::filesystem::current_path(parentPath);
|
||||
}
|
||||
else
|
||||
std::filesystem::current_path(path);
|
||||
}
|
||||
|
||||
WorkingDirectory::~WorkingDirectory() { std::filesystem::current_path(previous); }
|
||||
}
|
||||
21
src/util/working_directory.h
Normal file
21
src/util/working_directory.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace anm2ed::util
|
||||
{
|
||||
class WorkingDirectory
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
FILE,
|
||||
DIRECTORY
|
||||
};
|
||||
|
||||
std::filesystem::path previous{};
|
||||
|
||||
WorkingDirectory(const std::filesystem::path&, Type type = DIRECTORY);
|
||||
~WorkingDirectory();
|
||||
};
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "xml_.h"
|
||||
|
||||
#include "filesystem_.h"
|
||||
#include "math_.h"
|
||||
#include "path_.h"
|
||||
|
||||
using namespace anm2ed::util;
|
||||
using namespace tinyxml2;
|
||||
namespace filesystem = anm2ed::util::filesystem;
|
||||
|
||||
namespace anm2ed::util::xml
|
||||
{
|
||||
@@ -27,7 +27,7 @@ namespace anm2ed::util::xml
|
||||
{
|
||||
std::string temp{};
|
||||
auto result = query_string_attribute(element, attribute, &temp);
|
||||
if (result == XML_SUCCESS) *out = filesystem::path_from_utf8(temp);
|
||||
if (result == XML_SUCCESS) *out = path::from_utf8(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user